1 2 Previous Next 16 Replies Latest reply on Nov 26, 2019 6:50 PM by 1812359

    self.connected runs twice when navigating back? Proper usage?

    1812359

      Hi,

       

      I have a module that populates a listView from a REST service, I have filled this listView with data in the self.connected() function. This seemed to work well, however, I have found that when I leave the page and then navigate back to it with the router.go functionality the self.connected() seems to run twice? I can't see why this is?

       

      Am i using this in the wrong way? Should I not be retrieving the data for the page in the self.connected function?

        • 1. Re: self.connected runs twice when navigating back? Proper usage?
          1812359

          Ok,

          So after more debugging it's not that self.connected() runs twice, it's that the entire viewModel for some reason runs twice when navigating to a page or back.

           

          I can't figure this out, I have outputted to the console when the page is entered, etc, and the logic all runs twice. I also put some logging on the 'loadModule' function in appController.js and somehow that is getting invoked twice when navigating back to a page. I just cant figure out what is actually calling loadModule 2 times... This is becoming a real hinderance as the REST calls get invoked twice, etc.

           

          I started with the default navBar template and havent made a lot of changes. When I navigate manually I am using the router.go('page') command, but other than that the navigation happens via the navBar.

           

          Any help is greatly appreciated.

          • 2. Re: self.connected runs twice when navigating back? Proper usage?
            1812359

            Hi All,


            I'm getting very frustrated with this issue. Whenever I go to a page for the second, third, fourth, etc time the page seems to load twice. I have console logging to tell me when the viewModel code is executed, when the connected() code is executed, and it all gets executed twice.

             

            Why would this be? I have done endless debugging but I can't see how its happening. I am navigating to the pages using the self.router.go('module').. could the router somehow be causing things to load twice??

            • 3. Re: self.connected runs twice when navigating back? Proper usage?
              Natalia Balatskova-Oracle

              Does it happen without your changes? If you create a separate app based navBar template, do you see the same issue?

              Did you create extra knockout dependencies, that trigger the updates twice?

              • 4. Re: self.connected runs twice when navigating back? Proper usage?
                1812359

                I'm not aware of any dependencies I have, it seems more app wide which is why i am assuming it is the router. That was changed from default, I created a post a week or 2 back looking for help and tried to implement the parent/child routing, but guessing something is off there. For what its worth my router setup is below...

                 

                 

                            // Router setup

                 

                            self.router = Router.rootInstance;


                            self.router.configure({

                                'login': { label: 'Login', isDefault: true },

                                'home': {

                                    label: 'Home', canEnter: function () {

                                        return self.userLoggedIn() == 'Y';

                                    }

                                },

                                'cases': {

                                    label: 'Cases', canEnter: function () {

                                        return self.userLoggedIn() == 'Y';

                                    }

                                },

                                'call': {

                                    label: 'Call', canEnter: function () {

                                        return self.userLoggedIn() == 'Y';

                                    },

                                    value: self.router.createChildRouter('call').configure({

                                        'details': {

                                            label: 'Details',

                                            isDefault: true

                                        },

                                        'parts': {

                                            label: 'Parts'

                                        },

                                        'history': {

                                            label: 'History'

                                        },

                                        'dispatch': {

                                            label: 'Dispatch'

                                        },

                                        'machineinquiry': {

                                            label: 'Machine Inquiry'

                                        }

                                    })

                                },

                                'inventory': {

                                    label: 'Inventory', canEnter: function () {

                                        return self.userLoggedIn() == 'Y';

                                    }

                                },

                                'inventorydetail': {

                                    label: 'Inventory Detail', canEnter: function () {

                                        return self.userLoggedIn() == 'Y';

                                    }

                                },

                                'about': {

                                    label: 'About', canEnter: function () {

                                        return self.userLoggedIn() == 'Y';

                                    }

                                }

                            });


                            Router.defaults['urlAdapter'] = new Router.urlParamAdapter();


                            // Callback function that can return different animations based on application logic.

                            function switcherCallback(context) {

                                if (platform === 'android')

                                    return 'fade';

                                return null;

                            }

                            ;


                            self.moduleConfig = ko.observable({ 'view': [], 'viewModel': null });

                            //Trying parameter passing


                            self.loadModule = function () {

                                ko.computed(function () {

                                    console.log("In loadModule app Controller");

                                    var flowName = self.router.moduleConfig.name();

                                    var name = flowName;

                                    if (flowName && flowName === 'call') {

                                        name = flowName + '/' + self.router.getCurrentChildRouter().moduleConfig.name();

                                    }

                                    var viewPath = 'views/' + name + '.html';

                                    var modelPath = 'viewModels/' + name;

                                    console.log(`name: ${name} viewPath: ${viewPath} modelPath: ${modelPath}`);

                                    console.log("Router State ID: ", self.router.stateId());

                                    //   self.navDataProvider = new ArrayDataProvider(navData(), { keyAttributes: 'id' });

                                    var masterPromise = Promise.all([

                                        moduleUtils.createView({ 'viewPath': viewPath }),

                                        moduleUtils.createViewModel({ 'viewModelPath': modelPath })

                                    ]);

                                    masterPromise.then(

                                        function (values) {

                                            self.moduleConfig({ 'view': values[0], 'viewModel': values[1] });

                                        }

                                    );

                                });

                            };

                            self.moduleAnimation = ModuleAnimations.switcher(switcherCallback);


                            // Navigation setup

                            self.defaultnavData = [

                                {

                                    name: 'Home', id: 'home', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-home-icon-24'

                                },

                                {

                                    name: 'Cases', id: 'cases', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-catalog-icon-24'

                                },

                                {

                                    name: 'Inventory', id: 'inventory', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-library-icon-24'

                                },

                                {

                                    name: 'Sign Out', id: 'signout', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-signout-icon-24'

                                }

                            ];

                            //Case navigation

                            self.casenavData = [

                                {

                                    name: 'Details', id: 'call/details', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-edit-icon-24'

                                },

                                {

                                    name: 'Parts', id: 'call/parts', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-palette-icon-24'

                                },

                                {

                                    name: 'History', id: 'call/history', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-copy-icon-24'

                                },

                                {

                                    name: 'Machine', id: 'call/machineinquiry', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-info-icon-24'

                                },

                                {

                                    name: 'Dispatch', id: 'call/dispatch', loggedInOnly: true,

                                    iconClass: 'oj-navigationlist-item-icon demo-icon-font-24 demo-chat-icon-24'

                                }

                            ];


                            var navData = function () {

                                var flowName = self.router.moduleConfig.name();

                                console.log("In navData function: ", flowName);

                                if (flowName && flowName === 'call') {

                                    return self.casenavData;

                                }

                                else {

                                    return self.defaultnavData;

                                }

                            };


                            //    self.navDataProvider = new ArrayDataProvider(navData(), { keyAttributes: 'id' });

                            self.navDataProvider = ko.computed(function () {

                                return new ArrayDataProvider(navData(), { keyAttributes: 'id' });

                            });

                • 5. Re: self.connected runs twice when navigating back? Proper usage?
                  Natalia Balatskova-Oracle

                  Do you get the same problem without child router?

                  I'm looking at your

                  self.loadModule = function () {

                    ko.computed(function () { ... })

                  }

                  It creates one dependency on var flowName = self.router.moduleConfig.name();

                  Also it seems another dependency on on  self.router.getCurrentChildRouter().moduleConfig.name();

                  When you switch between views the flowName would change, what happens to the moduleConfig on the child router - is it updated as well? If yes, then the ko.computed() is triggered twice and module is loaded twice. Can you check?

                  • 6. Re: self.connected runs twice when navigating back? Proper usage?
                    1812359

                    I will check but I'm not doing anything else with the router apart from what you see in previous post.

                     

                    The only other thing I'm doing is issuing router.go commands at certain times during the code. When the flow does change I change the navbar the user sees so it corresponds with the proper flow.

                     

                    I know this is likely the wrong way to do this, but I couldn't make it work any other way.

                     

                    Basically I need the main navbar having a home, inventory, cases, sign out button. Then when a user selects cases they are moved to the default page of cases child router and the navbar changes to the "cases" flow and the router is the cases child router... This does seem to work with how things are setup thanks to some example from the blog Daniel replied with in the router post.

                     

                    I'm open to completely changing it to whatever is best practice but just need a little bit of guidance to set me straight on how to prevent this from happening?

                     

                    Thanks a lot for your time.

                    • 7. Re: self.connected runs twice when navigating back? Proper usage?
                      1812359

                      Hi Natalia Balatskova-Oracle

                       

                      Just wanted to say thanks, you were right about the dependency issue. Daniel Merchan kindly helped me through a way around it.

                       

                      The one item we are stuck with is that the navbar currently selected item does not change when the user navigates via the navbar. However, if I press a button and then refresh the page it does then highlight then the correct option on the navbar menu. Doing debugging the router.stateId is properly set to the correct module, etc. It just seems that the item doesnt show as selected until you refresh? It does actually navigate to the correct place, it just doesnt update the ui navbar to reflect this.

                       

                      For the selection= attribute of the navigation-list we are using a function that returns the correct state (this evaluates the child router, etc) and it does return the correct informaiton, it's just not reflected in the UI until refresh? Do you have any quick pointers on what to look for or how we can ensure this is set?


                      Thanks again.

                      • 8. Re: self.connected runs twice when navigating back? Proper usage?
                        Natalia Balatskova-Oracle

                        How do you setup an expression for the selection attribute and how do you define the function that calculates the selection state - is attribute update triggered on router.stateId change?

                        • 9. Re: self.connected runs twice when navigating back? Proper usage?
                          1812359

                          Hi,

                          My navigation-list currently looks like this:

                                    <oj-navigation-list id="navList" class="oj-navigationlist-stack-icon-label" data="[[navDataProvider]]"
                                                        edge="top" item.renderer="[[KnockoutTemplateUtils.getRenderer('navTemplate', true)]]"
                                                        on-oj-before-select="[[beforeNavigation]]" selection="{{currentSelection}}">
                                    </oj-navigation-list>
                          

                           

                          And then the beforeNavigation looks like:

                                      self.beforeNavigation = function (event) {
                                          if (event.detail.originalEvent) {
                                              event.preventDefault();
                                              // Invoke go() with the selected item.
                                              self.router.go(event.detail.key).then(function (values) {
                                                  self.loadModule();
                                              });
                                          }
                                      };
                          

                           

                           

                          And then the currentSelection looks like

                                      self.currentSelection = ko.computed(() => {
                                          let currentState = self.router.currentState(),
                                              childRouter, currentSelection;
                                          if (currentState && currentState.id) {
                                              childRouter = currentState.value;
                                              if (childRouter) {
                                                  currentSelection = childRouter.stateId();
                                              }
                                              if (currentSelection) {
                                                  currentSelection = currentState.id + '/' + currentSelection;
                                              }
                                              else {
                                                  currentSelection = currentState.id;
                                              }
                                          }
                                          console.log("Current selec: " + currentSelection);
                                          return currentSelection;
                                      });
                          

                           

                          These are the changes that we (Daniel) made to make sure the model doesnt load twice... calling the loadModule manually instead of the way we had it before where we had the ko.observable in the loadModule. This has made loading the pages work very nicely, the last remaining issue is this pesky navbar not showing the properly selected item.

                           

                          The loadModule now looks like this:

                                      self.loadModule = function () {
                                          self.moduleConfig(ModuleElementUtils.createConfig({ name: self.currentSelection() }));
                                      }
                          
                          • 10. Re: self.connected runs twice when navigating back? Proper usage?
                            Natalia Balatskova-Oracle

                            It looks that the value generated by the self.currentSelection() is incorrect - does not correspond to the navigation list item.

                             

                            In general it seems that you run into trouble because you want to use the same oj-module element to load views from both routers - a root router and a child router.

                            Is it necessary to use the child router in your case? Did you review the 'Nested Child Routers' demo: https://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=router&demo=views  ?

                            If you need to use nested routers, it will be better to use nested oj-module elements as well. So your 'call' view will have a separate oj-module element that will manage child router states - 'detail', 'parts', etc and the 'call' view model will be responsible for loading views for those states. That would make the code more manageable and you will be able to avoid the unwanted dependencies in the computed observables.

                            • 11. Re: self.connected runs twice when navigating back? Proper usage?
                              1812359

                              But that's the strange thing, the result from self.currentSelection() is correct, I have verified in the console. When refreshing the page manually it is able to highlight the right item.

                               

                              I have looked at the nested router section of the cookbook for hours and hours and was unable to make progress, the examples don't really match the way things are done in the starter templates and when I try to adapt it things just didn't work correctly. I created a post about it a few weeks back and Daniel kindly responded with an example he did a while ago, so I adopted a similar approach from his blog post, this has at least gotten me a lot further. Maybe you're right and I don't need a child router, as I have defined "sub" menu flows I thought child routers made the most sense... maybe I just add everything to the main router and display different navBars based on the current module. However, to make things manageable I would at least like to split modules up into sub folders... would I just hardcode the view and viewmodel path for all possible scenarios in the loadModule function, or would there be a better way to do that?

                               

                              It would be very helpful if there was a demo project out there using the same concepts as the 7.2 starter templates (with the loadModule() ) that utilises child routing. The FixitFast demo app uses a completely different approach and some of the concepts it uses arent really documented, so have been spinning my wheels a bit.

                               

                              Thanks for your time, I do appreciate it.

                              • 12. Re: self.connected runs twice when navigating back? Proper usage?
                                1812359

                                Also,

                                 

                                I put everything back to default (router, navBar, etc).

                                 

                                The only thing I added was a login page (set as default in the router), after successful login I issue a router.go('home') command. This works and I am directed 'home' however the Home icon is not highlighted. When I click other buttons after this they do get highlighted properly.

                                 

                                Is there a way we can ensure something is selected at the UI layer?

                                • 14. Re: self.connected runs twice when navigating back? Proper usage?
                                  1812359

                                  Thanks,

                                   

                                  I have looked at that, will need to give it another shot.

                                   

                                  I think I am going to take a step back and just do everything with the parent for now.. do you know how to fix the issue of the item not initially being highlighted in the navbar?

                                   

                                  I have the navBar starter template, all that I have changed is having a new module, login, set as default. Once a user logs in I issue a router.go command to 'home'. The navigation works but the navBar doesnt reflrect the fact Home is active, nothing is selected on the navBar until i refresh or select something else?

                                  1 2 Previous Next