9 Replies Latest reply on Feb 14, 2019 4:19 PM by J-Lig

    IG custom row actions menu - Duplicate

    partlycloudy

      APEX 18.2

       

      Follow-up to adding a custom menu item to the Interactive Grid Row Actions menu as discussed in this thread.

       

      The IG has multiple alternative default reports defined. Whenever the report view is changed, the custom menu items are added over and over!

       

      https://apex.oracle.com/pls/apex/f?p=1855:35  is an example

       

       

      Strange because I see code to specifically handle this condition in John's example

       

      // do this after the page loads but before the IG is initialized to catch the initial events
      $(function() {
        // listen for view change events to find out when grid views are created 
        $("#emp").on("interactivegridviewchange", function(event, data) {
        if ( data.view === "grid" && data.created ) {
        var view = apex.region("emp").widget().interactiveGrid("getViews", "grid"),
        menu$ = view.rowActionMenu$;
      
        menu$.menu("option").items.push({

       

      Any ideas?

        • 1. Re: IG custom row actions menu - Duplicate
          Pierre Yotti

          partlycloudy

           

          OK. I have tested it and I do not have this problem.

          Can you please provide more information on how you add added the custom action menu Item?

           

           

          Demo

          https://apex.oracle.com/pls/apex/f?p=23342:28

           

          Username/Password:demo/demo

          • 2. Re: IG custom row actions menu - Duplicate
            partlycloudy

            Well, that's because your example puts the JS code in Execute When Page Loads and my  example does it by binding to the interactivegridviewchange event as John recommends!

             

            Your example clearly works, no doubt about it but John's comments in the code and his blog post make sense as well. After all, John has written this entire component so I decided to follow his recommendation over yours!

             

            John Snyders-Oracle

            • 3. Re: IG custom row actions menu - Duplicate
              Pierre Yotti

              What you try to solve does not have something to do with the IG. It is just Javascript.

              You are try to add the custom Menu Item each Time in the Action Menu Row  if the View changed. It is normal.

              Instead of copy the Code, you should try to understand it.

               

              - One possibility is to check each time if the menu item is already there

               

              $(function() {

                  // listen for view change events to find out when grid views are created

                  $("#dept").on("interactivegridviewchange", function(event, data) {

                      if ( data.view === "grid" && data.created ) {

                          view = apex.region("dept").widget().interactiveGrid("getViews", "grid");

                          menu$ = view.rowActionMenu$;

                          var items=menu$.menu("option").items;

                          var item = {

                              type:"action",

                              label:"Recalculate salary",

                              icon: "fa fa-calculator",

                               id:'calcul',

                              action: function(menu, element) {

                                  record = view.getContextRecord( element )[0];

                                  record1 = view.getContextRecord(element);

                                  var deptno = view.model.getValue(record, "DEPTNO");

                                  sendToServer(deptno,'Calculate_Salary','#dept',view,record1);                       

                              }

                            };

                          if(items[3].id==='calcul'){

                       

                          }else{

                               items.splice(3,0,item);

                          }

                    

                      }

                  });

              });

               

               

              - The other possibility and the best. Because is just check if the action with id "calcul" is already there.

              Here it does not matter in which position the item is located

               

              $(function() {

                  // listen for view change events to find out when grid views are created

                  $("#dept").on("interactivegridviewchange", function(event, data) {

                      if (data.view === "grid" && data.created) {

                          view = apex.region("dept").widget().interactiveGrid("getViews", "grid");

                          menu$ = view.rowActionMenu$;

                          var items = menu$.menu("option").items;

                          var item = {

                              type: "action",

                              label: "Recalculate salary",

                              icon: "fa fa-calculator",

                              id: 'calcul',

                              action: function(menu, element) {

                                  record = view.getContextRecord(element)[0];

                                  record1 = view.getContextRecord(element);

                                  var deptno = view.model.getValue(record, "DEPTNO");

                                  sendToServer(deptno, 'Calculate_Salary', '#dept', view, record1);

                              }

                          };

               

               

                          var found = items.some(function(el) {

                              return el.id === 'calcul'

                          });

               

               

                          if (!found) {

                              items.splice(3, 0, item);

                          }

               

               

               

               

               

               

                      }

                  });

              });

               

              Demo

              https://apex.oracle.com/pls/apex/f?p=23342:29

              • 4. Re: IG custom row actions menu - Duplicate
                partlycloudy

                What you try to solve does not have something to do with the IG. It is just Javascript.

                Yes, I understand that it is just Javascript but the IG API and widgets and events thereof (e.g. interactivegridviewchange) are specific to the APEX IG component so I am trying to make sure we extend it appropriately instead of blindly hacking it.

                 

                Instead of copy the Code, you should try to understand it.

                Your prompt help on a public, volunteer forum is greatly appreciated but I think this comment is uncalled for. I believe my record on this forum speaks for itself. The questions I ask, my attempts to find a solution, demonstrate with examples on apex.oracle.com  and conclude every thread by updating my example with the Accepted or Helpful answer received, IMHO attest to the fact that I am not just copying the code, I understand it completely. My comment in the earlier post about  that's because your example puts the JS code in Execute When Page Loads and my  example does it by binding to the interactivegridviewchange event as John recommends! is another case in point.

                 

                One possibility is to check each time if the menu item is already there

                 

                Yes, clearly that is an obvious solution but that begs the question..why not just add the menu item in the Page Load function so it is guaranteed to be called exactly once?!

                 

                // do this after the page loads but before the IG is initialized to catch the initial events  
                $(function() {  
                  // listen for view change events to find out when grid views are created   
                  $("#emp").on("interactivegridviewchange", function(event, data) {  
                  if ( data.view === "grid" && data.created ) {  
                
                
                

                 

                To me, the following points are still unclear

                 

                1. What does John mean by the comment in Line 1? In other words, what is the advantage over just executing this code at Page Load? The example in the documentation has a comment // Define in the 'Function and Global Variable Declaration' page attribute (not 'Execute when Page Loads'), in order to be active by the time the Interactive Grid is initialized. but I don't quite understand it.

                 

                2. I was giving John the benefit of the doubt by assuming that the data object passed to the callback would have the created property set to true, quoting from the documentation, If true this indicates the view has just been created (or viewed for the first time). and not every time the view is selected from the Reports menu. As it stands, this is a very obvious bug in John's example and that's what prompted my question to the forum.

                 

                3. In a page where the IG grid view is NOT the default view on page load, I thought this technique to use the interactivegridviewchange event and inspecting data.view==="grid" would be necessary, but even here, simply adding the menu item on page load works just fine!

                 

                Thanks

                • 5. Re: IG custom row actions menu - Duplicate
                  J-Lig

                  Hi partlycloudy,

                   

                  We just upgraded to 18.2 earlier this week and we are having the same issues. This worked fine in 5.1. It appears that there has been a change to the method/timing of the action menu creation. We are now experiencing the same thing. On page load, it creates the menu nicely, then each time the saved report selector is changed it adds another copy of my button. I can think of several ways to handle this, but I am looking for the "preferred" method. Or at least some understanding for when these menus are created vs just re-rendering it so that I can decide the best way to handle it. Did you ever get an answer? What method did you end up choosing to remedy this? 

                  Thank you,

                  Jen

                  • 6. Re: IG custom row actions menu - Duplicate
                    partlycloudy

                    I ended up adding the menu on page load as I described in my last post and linked to example pages to demonstrate. You can examine the code on the page for details. 

                     

                    The questions I posed still stand. Only John Snyders-Oracle can answer them!

                    • 7. Re: IG custom row actions menu - Duplicate
                      J-Lig

                      OK, cool. I just wanted to make sure because it would not work at all in previous versions if you added the menu code to the "Execute when Page Load." I started out updating my code to check to see if it already existed before creating buttons (which I guess is a good idea anyway), but then decided that I also wanted to make sure I had it in the correct place so that it would not be attempting to create it multiple times to begin with.

                       

                      Thank you,

                      Jen

                      • 8. Re: IG custom row actions menu - Duplicate
                        John Snyders-Oracle

                        Hi,

                        partlycloudy wrote:

                        ...

                        To me, the following points are still unclear

                         

                        1. What does John mean by the comment in Line 1? In other words, what is the advantage over just executing this code at Page Load? The example in the documentation has a comment // Define in the 'Function and Global Variable Declaration' page attribute (not 'Execute when Page Loads'), in order to be active by the time the Interactive Grid is initialized. but I don't quite understand it.

                         

                        2. I was giving John the benefit of the doubt by assuming that the data object passed to the callback would have the created property set to true, quoting from the documentation, If true this indicates the view has just been created (or viewed for the first time). and not every time the view is selected from the Reports menu. As it stands, this is a very obvious bug in John's example and that's what prompted my question to the forum.

                         

                        3. In a page where the IG grid view is NOT the default view on page load, I thought this technique to use the interactivegridviewchange event and inspecting data.view==="grid" would be necessary, but even here, simply adding the menu item on page load works just fine!

                         

                        Thanks

                        1) This is all about timing. If you look at the page source and see where IG init code goes and where Execute when Page Load code goes you will see that the IG is initialized first.

                        When IG is initialized it fires some events. If you add event handlers to Execute when Page Loads you will miss those events. You typically don't want to run code from Function and Global Variable Declaration but you can add code that runs when the document is ready. That is what $(function() ... ) does. jQuery ready handlers are executed in the order they are added. So the code added to $(function()...) in Function and Global Variable Declaration runs after the document is ready but before the IG is initialized so that it can listen for events that are fired by IG as it is initialized.

                         

                        2) Yes this bug with duplicate row or selection action menu items is in a few places in the Cookbook. This is a matter of me forgetting how IG works and how it has changed over time. Originally the row and selection menus were created each time the grid view is created. Then sometime around 5.1.4 or so it changed so that views could do global initialization just once and this is where the grid view created its row and selection menus. I forgot about this and even worked around the issue on the IG Cookbook tasks page with the following code in the Tasks.js file:

                         

                        var ...

                            menu$ = view.selActionMenu$;

                         

                        // it may be a bug but this can happen even if the menu is already created.

                        // so check if we already added the items so don't do it multiple times

                        if (!menu$.menu("find", "complete")) {

                            // now add items to the menu that reference actions added to the IG

                            // see IG attribute Advanced JavaScript Code

                            items = menu$.menu( "option" ).items;

                            ....

                            items.push( {

                                type: "action",

                                action: "selection-move-up"

                            } );

                            items.push( {

                                id: "complete",

                                type: "action",

                                action: "selection-complete"

                            } );

                            ...

                         

                        I had totally forgotten about the change that I had made to initialize the menus just once.

                         

                        3) I think it works in this case because all defined views do the global just once initialization (init method) when the IG widget is created. Then the default current view is initialized (initView method)

                         

                        So I think that updating the menu just once on page load is probably the correct thing to do now. I will verify this when I next update the IG Cookbook app.

                         

                        To be clear the interactivegridviewchange event is fired correctly in that the view is being created it is just that the menus are not.

                         

                        There are other cases where you do need to listen for the view being created but they are probably rare.

                         

                        Regards,
                        -John

                        1 person found this helpful
                        • 9. Re: IG custom row actions menu - Duplicate
                          J-Lig

                          Thank you for your response John. Based on what I was seeing, I had a feeling that is what happened. It is nice to get actual confirmation though.