Forum Stats

  • 3,735,212 Users
  • 2,247,145 Discussions
  • 7,857,787 Comments

Discussions

Add Button to Card?

Bud Endress - Oracle-Oracle
Bud Endress - Oracle-Oracle Member Posts: 280 Employee
edited Aug 4, 2020 2:46PM in APEX Discussions

I'm looking to add a button to a card that when clicked calls a PL/SQL procedure.  The purpose is to mark a card as a 'favorite'.  Probably simple stupid, but I haven't found an example.  If would best if if wasn't JavaScript (because I'm not a JavaScript programmer), but if the example is very simple I might be able to follow it.  As an alternative to a button I can use a text string that when clicked called a PL/SQL procedure.

Gabriel GuzmanjariolaVeerendra Patil

Best Answer

  • fac586
    fac586 Senior Technical Architect Member Posts: 19,680 Black Diamond
    edited Jul 30, 2020 4:14PM Accepted Answer

    I suspect that this is probably not as simple as you'd like. I've tried to minimise the JavaScript as much as possible, but to do without it completely would result in an extremely clunky user experience.

    In the report query the only modification required is to conditionally return an is-favorite class name in the CARDS_MODIFIER column:

    select    e.first_name || ' ' || e.last_name                            card_title  , j.job_title                                                   card_subtitle  , d.department_name                                             card_text  , null                                                          card_subtext  , case fav.is_favorite      when 1 then 'is-favorite'      else null    end                                                           card_modifiers  , '#' || e.employee_id                                          card_link  , null                                                          card_color  , null                                                          card_icon  , apex_string.get_initials(e.first_name || ' ' || e.last_name)  card_initials  , l.street_address  , l.city  , l.state_province  , c.country_name  , e.employee_idfrom    oehr_employees e      join oehr_jobs j        on e.job_id = j.job_id      join oehr_departments d        on e.department_id = d.department_id      join oehr_locations l        on d.location_id = l.location_id      join oehr_countries c        on l.country_id = c.country_id      ...where   ...

    Then create the Add/Remove Favorite buttons by adding this code to the HTML Expression property of the CARD_SUBTEXT column. If you already have content in CARD_SUBTEXT then reference it before this using substitution references to the relevant column(s):

    <div><!-- Reference existing CARD_SUBTEXT column(s) here -->#STREET_ADDRESS#<br/>#CITY#<br/>#STATE_PROVINCE#<br/>#COUNTRY_NAME#</div><div class="card-favorite u-pullRight">  <button type="button" title="Add as favorite" aria-label="Add as favorite" class="add t-Button t-Button--noLabel t-Button--icon t-Button--small t-Button--noUI" data-card-id="#EMPLOYEE_ID#">    <span aria-hidden="true" class="t-Icon fa fa-plus-circle-o"></span>  </button>  <button type="button" title="Remove as favorite" aria-label="Remove as favorite" class="remove t-Button t-Button--noLabel t-Button--icon t-Button--small t-Button--noUI" data-card-id="#EMPLOYEE_ID#">    <span aria-hidden="true" class="t-Icon fa fa-minus-circle-o"></span>  </button></div>

    Note the data-card-id attributes at lines 3 & 6. Replace the column references here with whatever unique card identifier is passed to the PL/SQL procedure.

    Add a hidden, unprotected PX_CARD_ID page item to use in passing these card ID parameters from the browser to the database.

    Display of the relevant Add/Remove button depending on whether the card is a favorite or not is controlled by a CSS style sheet. Place this in the page Inline CSS property:

    .card-favorite button.remove,.is-favorite .card-favorite button.add {  display: none;}.is-favorite .card-favorite button.remove {  display: inline-block;}

    Everything else is implemented using a Click dynamic action:

    Event: Click

    Selection Type: jQuery Selector

    jQuery Selector: .card-favorite button

    Client-side Condition Type: JavaScript Expression

    JavaScript Expression: $(this.triggeringElement).hasClass('add')

    Event Scope: Dynamic

    True Actions

    Action: Set Value

    Set Type: JavaScript Expression

    JavaScript Expression: this.triggeringElement.dataset.cardId

    Affected Element Selection Type: Item(s)

    Item(s): PX_CARD_ID

    Fire on Initialization: Off

    Action: Execute PL/SQL Code

    Items to Submit: PX_CARD_ID

    Fire on Initialization: Off

    PL/SQL Code:

    /* Invoke PL/SQL procedure to set card as favorite */

    Action: Add Class

    Class: is-favorite

    Selection Type: JavaScript Expression

    JavaScript Expression: $(this.triggeringElement).closest('.t-Cards-item')

    Action: Cancel Event

    False Actions

    Action: Set Value

    Set Type: JavaScript Expression

    JavaScript Expression: this.triggeringElement.dataset.cardId

    Affected Element Selection Type: Item(s)

    Item(s): PX_CARD_ID

    Fire on Initialization: Off

    Action: Execute PL/SQL Code

    Items to Submit: PX_CARD_ID

    Fire on Initialization: Off

    PL/SQL Code:

    /* Invoke PL/SQL procedure to remove card as favorite */

    Action: Remove Class

    Class: is-favorite

    Selection Type: JavaScript Expression

    JavaScript Expression: $(this.triggeringElement).closest('.t-Cards-item')

    Action: Cancel Event

    Gabriel Guzmanjariola

Answers

  • fac586
    fac586 Senior Technical Architect Member Posts: 19,680 Black Diamond
    edited Jul 30, 2020 12:02PM
    Bud Endress - Oracle-Oracle wrote:I'm looking to add a button to a card that when clicked calls a PL/SQL procedure. The purpose is to mark a card as a 'favorite'. Probably simple stupid, but I haven't found an example. If would best if if wasn't JavaScript (because I'm not a JavaScript programmer), but if the example is very simple I might be able to follow it. As an alternative to a button I can use a text string that when clicked called a PL/SQL procedure.

    What label/icon is going to appear on the button?

    Where should the button appear on the card?

    Is the cards region a list or a report?

    Does being designated a "favorite" alter the state or appearance of the card in any way (e.g. different card color/icon/initials, or the button disappears or its label/icon changes)?

    Is there a limit on the number of cards that can be designated as "favorites"?

  • Bud Endress - Oracle-Oracle
    Bud Endress - Oracle-Oracle Member Posts: 280 Employee
    edited Jul 30, 2020 12:24PM

    Thanks for the reply.  I'm looking for something very simple.  A small button anywhere near the bottom of the card (or a text string, e.g., "Favorite").  Nothing else able the card needs to change.  All it needs to do is call a PL/SQL procedure that will flip the value in a column from 0 to 1 or 1 to 0.  That flag will be used to filter the cards displayed to the user via filter in the WHERE clause of the report. (E.g, SELECT a,b,c, FROM table WHERE is_favorite = 1.

    The is no limited to the number of cards that can be favorites, but in practice the universe of cards will not exceed 100.

  • fac586
    fac586 Senior Technical Architect Member Posts: 19,680 Black Diamond
    edited Jul 30, 2020 12:59PM

    One last thing: do the cards function as links?

  • Bud Endress - Oracle-Oracle
    Bud Endress - Oracle-Oracle Member Posts: 280 Employee
    edited Jul 30, 2020 1:13PM

    Yes, the cards function as links (hence I need a different mechanism for calling the PL/SQL than just clicking the card).

    Again, my requirements are very modest.  Even being able to call PL/SQL by clicking on the card subtext (or something like that) would be just fine.

    I'm more core database, just learning APEX, so it might appear to be a very simple question.

  • fac586
    fac586 Senior Technical Architect Member Posts: 19,680 Black Diamond
    edited Jul 30, 2020 4:14PM Accepted Answer

    I suspect that this is probably not as simple as you'd like. I've tried to minimise the JavaScript as much as possible, but to do without it completely would result in an extremely clunky user experience.

    In the report query the only modification required is to conditionally return an is-favorite class name in the CARDS_MODIFIER column:

    select    e.first_name || ' ' || e.last_name                            card_title  , j.job_title                                                   card_subtitle  , d.department_name                                             card_text  , null                                                          card_subtext  , case fav.is_favorite      when 1 then 'is-favorite'      else null    end                                                           card_modifiers  , '#' || e.employee_id                                          card_link  , null                                                          card_color  , null                                                          card_icon  , apex_string.get_initials(e.first_name || ' ' || e.last_name)  card_initials  , l.street_address  , l.city  , l.state_province  , c.country_name  , e.employee_idfrom    oehr_employees e      join oehr_jobs j        on e.job_id = j.job_id      join oehr_departments d        on e.department_id = d.department_id      join oehr_locations l        on d.location_id = l.location_id      join oehr_countries c        on l.country_id = c.country_id      ...where   ...

    Then create the Add/Remove Favorite buttons by adding this code to the HTML Expression property of the CARD_SUBTEXT column. If you already have content in CARD_SUBTEXT then reference it before this using substitution references to the relevant column(s):

    <div><!-- Reference existing CARD_SUBTEXT column(s) here -->#STREET_ADDRESS#<br/>#CITY#<br/>#STATE_PROVINCE#<br/>#COUNTRY_NAME#</div><div class="card-favorite u-pullRight">  <button type="button" title="Add as favorite" aria-label="Add as favorite" class="add t-Button t-Button--noLabel t-Button--icon t-Button--small t-Button--noUI" data-card-id="#EMPLOYEE_ID#">    <span aria-hidden="true" class="t-Icon fa fa-plus-circle-o"></span>  </button>  <button type="button" title="Remove as favorite" aria-label="Remove as favorite" class="remove t-Button t-Button--noLabel t-Button--icon t-Button--small t-Button--noUI" data-card-id="#EMPLOYEE_ID#">    <span aria-hidden="true" class="t-Icon fa fa-minus-circle-o"></span>  </button></div>

    Note the data-card-id attributes at lines 3 & 6. Replace the column references here with whatever unique card identifier is passed to the PL/SQL procedure.

    Add a hidden, unprotected PX_CARD_ID page item to use in passing these card ID parameters from the browser to the database.

    Display of the relevant Add/Remove button depending on whether the card is a favorite or not is controlled by a CSS style sheet. Place this in the page Inline CSS property:

    .card-favorite button.remove,.is-favorite .card-favorite button.add {  display: none;}.is-favorite .card-favorite button.remove {  display: inline-block;}

    Everything else is implemented using a Click dynamic action:

    Event: Click

    Selection Type: jQuery Selector

    jQuery Selector: .card-favorite button

    Client-side Condition Type: JavaScript Expression

    JavaScript Expression: $(this.triggeringElement).hasClass('add')

    Event Scope: Dynamic

    True Actions

    Action: Set Value

    Set Type: JavaScript Expression

    JavaScript Expression: this.triggeringElement.dataset.cardId

    Affected Element Selection Type: Item(s)

    Item(s): PX_CARD_ID

    Fire on Initialization: Off

    Action: Execute PL/SQL Code

    Items to Submit: PX_CARD_ID

    Fire on Initialization: Off

    PL/SQL Code:

    /* Invoke PL/SQL procedure to set card as favorite */

    Action: Add Class

    Class: is-favorite

    Selection Type: JavaScript Expression

    JavaScript Expression: $(this.triggeringElement).closest('.t-Cards-item')

    Action: Cancel Event

    False Actions

    Action: Set Value

    Set Type: JavaScript Expression

    JavaScript Expression: this.triggeringElement.dataset.cardId

    Affected Element Selection Type: Item(s)

    Item(s): PX_CARD_ID

    Fire on Initialization: Off

    Action: Execute PL/SQL Code

    Items to Submit: PX_CARD_ID

    Fire on Initialization: Off

    PL/SQL Code:

    /* Invoke PL/SQL procedure to remove card as favorite */

    Action: Remove Class

    Class: is-favorite

    Selection Type: JavaScript Expression

    JavaScript Expression: $(this.triggeringElement).closest('.t-Cards-item')

    Action: Cancel Event

    Gabriel Guzmanjariola
  • Bud Endress - Oracle-Oracle
    Bud Endress - Oracle-Oracle Member Posts: 280 Employee
    edited Jul 30, 2020 4:32PM

    Thank you very much.  It will take me a bit of time to work through this.  I'll like you know how I make out with this.

  • Veerendra Patil
    Veerendra Patil Member Posts: 537 Gold Badge
    edited Jul 30, 2020 4:42PM

    Hi @fac586,

    Just a small question on this - (May be I am wrong

    If we have

    <a href="url1">

         <span onClick="url2" class="button"> </span>

    </a>

    When I click on span button, both the links url2, and url1 are fired.. Why?

    Should only url2 fire? or only url1 ?

    I have created an example on apex.oracle.com

    ws - vpagmws

    user - testuser

    pwd - [email protected]

    app - 69143 - VP Test APP

    page - 52

    Thanks

  • fac586
    fac586 Senior Technical Architect Member Posts: 19,680 Black Diamond
    edited Jul 31, 2020 6:28AM
    Veerendra Patil wrote:Just a small question on this - (May be I am wrongIf we have <a href="url1"> <span onClick="url2" class="button"> </span></a>When I click on span button, both the links url2, and url1 are fired.. Why?

    The click event propagates ("bubbles") up through the ancestors of the target element, triggering any handlers for the event that exist thereon.

    Should only url2 fire? or only url1 ?

    It depends. Which do you want? By default both will fire, following the defined event propagation model. It's the responsibility of the developer to control and respond to event propagation according to the requirements of the application. The single most important thing in my demo above is the use of Cancel Event actions to prevent clicking the button triggering the link on the parent element.

    Veerendra Patil
  • acowling-Oracle
    acowling-Oracle Posts: 12 Employee
    edited Jul 31, 2020 9:21AM

    Coincidentally I just stumbled across this blog post about marking a card as a favourite which might be relevant

    http://www.laureston.ca/2019/03/29/drool-worthy-apex-cards-with-images-and-buttons/

    HTH - Andy

Sign In or Register to comment.