Why is the controller for a view loaded twice? - angularjs

Please check this plunk for the issue I am explaining below.
When you run the plunk you will observe that there are certain tabs. The first tab Home belongs to home state. The remaining tabs belong to category state each tab identified by a category ID.
When I am currently on Home tab and I click on some other tab, the CategoriesController is invoked just once as expected. But when I click on some other tab from there the CategoriesController is invoked multiple times, once for the previous tab and twice for the newly selected tab. Please run the plunker and observer the browser console to better understand it.
I do not know why the controller is invoked for the previous tab also. Any help would be appreciated.

Not sure about the reason of invoking controllers multiple times. I'm trying to figure out the problem but till then you can do the following:
Remove controller: "CategoriesController" from the state configuration
Add ng-controller="CategoriesController" to the ui-view="categories" element
This will work for now since only that view -> controller will be invoked which is active.
Edit:
Got the problem, you have the ui-view="categories" in each tab so n number of ui-view are being rendered for n number of your tabs.
Now what is actually happening, to provide the slide animation, Angular material is keeping the left and right tab available in the DOM as well.
So when you are clicking from Home (i.e. first tab) to another tab, it's working fine. But when you are going from any other tab (other than 1st tab), it's respective left & right tab are coming into action as well since the sliding effect needs to be performed.

U are changing seletedTab value in your CategoriesController and $stateChangeStart $watcher.but at the same time u are using ui-view with ng-if which need the seletedTab as a parameter.
Say currently u are on tab 0, and switching to tab 1. And Things happens like this:
First of all, ur state change start.In the $stateChangeStart watcher, the selectedTab is set to 1.
The ui-view in tab 0 is removed from DOM.
The ui-view in tab 1 is added to DOM, but currently the $stateParams.catID is still 0.In this way, it initiated the CategoriesController with $stateParams.catID = 0. And at the same time, it set the seletedTab to 0. This is the first invoke for previous Controller
The ui-view in tab 1 is removed from DOM and ui-view in tab 0 is added to DOM.
Then ur $state changed successfully. The ui-view in tab 0 inited the CategoriesController with $stateParams.catID = 1 and set the seletedTab to 1.This is the first invoke for next Controller
OK now the ui-view in tab 0 is removed and the ui-view in tab 1 is added to DOM again and finally inited the CategoriesController with $stateParams.catID = 1. Everything looks OK though. This is the second invoke for next Controller
Hope i made it clear.

Related

Tab is not switching but the URL of that tab is changing

I am using tabstrip and angular UI routing to navigate those tabs. When I click on the tab, its URL changes but the tab does not switch.
I have 3 tabs. The first 2 tabs work as expected. But the last tab does not switch even though its URL changes.
Here is my code.
Please let me know if you need further information.
It appears you have the k-state-active class set on a particular li, since you're using ui-sref you can use ui-sref-active="k-state-active" on all the li elements instead of the class you have on the first, the ui-sref-active state will apply the https://github.com/angular-ui/ui-router/wiki/quick-reference#ui-sref-active

$anchorScroll and $location only work after second try

I am trying to use $anchorScroll and $location.hash() to scroll to a div. I have a bottom on the top of the page. When I click the bottom, I want the page to scroll down to the bottom of the page where I have a <div id="target">.
For some reason, the first time I click the button, my page doesn't scroll. If a click a second time, the page does scroll. And afterwards the scrolling works fine. This weird behavior can be reproduced if I refresh my page.
I have this code in my controller:
$scope.scrolldown = function() {
$location.hash('target');
$anchorScroll();
}
I know that the $location.hash('target') line is supposed to append a hash value to the end of my URL.
Here's the URL when my page first got loaded:
http://run.plnkr.co/iqvdGjdeCP4idP4D/
After I clicked my button for the 1st time, it becomes:
http://run.plnkr.co/iqvdGjdeCP4idP4D/#/target
which was not right (and the page was not scrolling properly).
After I clicked my button for the 2nd time, it becomes:
http://run.plnkr.co/iqvdGjdeCP4idP4D/#/target#target
From this point on the page started to scroll properly, but the URL still looks very strange to me -- why would I want two hash values?
I want to know why the button only works after second click and how to correct it.
Update
I added routing to my code and the scroll is working fine now.
Here's my plunker demo with routing.
Take a look at this question, which contains a possible solution for you:
Supress reloading of ui-router based view on query parameter change
It works the second time you click the button because the hash doesn't change (and so the route doesn't reload). Notice the page flickering when you click it the first time? That's an indicator that the whole DOM has been re-rendered.

Controller included after $stateChangeSuccess is fired

I have a menu navigation bar that is made of several accordion widgets, and uses ng-include to include every section of the menu separately.
Some of these sections contains sub-sections that are also included through ng-include.
The first level accordion successfully uses the
$rootScope.on('$stateChangeSuccess')
to open the corresponding section based on the url, so that for example if the user opens a page that is supposed to have a certain accordion opened, it will automatically open even if you reload the page or share the link. I used the same code in the inner controller to sync the inner accordion as well, but to no avail. It appears that the second controller is initialized after the event was already fired. Is there a way I can fix this?

AngularJS: Two Parallel Views, One URL

I'm building a dashboard/control panel app that is basically made up of two tabs (bootstrap) at the root level, called "dispatch" and "admin". Each tab has a good bit of its own multi-tiered navigation and functionality, and they don't need to directly interact with each other. The problem I'm running into is how to deep-link to sub-views within one of the tabs without losing the "state" of the inactive tab. To clarify, I can achieve this just fine if I don't worry about updating the URL, but when I try to add deep-linking, that's when I get stuck.
An example of the desired behavior:
When you click on the "Admin" tab, the route becomes "/admin"
Click on a sub-nav item, route becomes "/admin/foo"
Select 3rd-tier sub-level item, route becomes "admin/foo/thing1"
Click on the "dispatch" tab, route becomes "/dispatch"
Click back on the "admin" tab, route goes back to "admin/foo/thing1"
So basically, if you're at the "admin/foo/thing1" route in the middle of filling out a text field, then switch to another tab, then switch back, the text field should still be there just as you left it.
Like I said, the problem isn't switching from tab to tab, since by default the tabs just show and hide things on the page without reloading any views dynamically. I just don't know how to deep-link to a given tab's "bookmarked" position when you switch to it. The way I keep thinking of it is that clicking on a tab should only update the first segment of the URL(/admin or /dispatch), and then some sort of $watch function would update the remaining segments based on the last "location" within that tab. Would something like that work?
Also, I'm using ui-router to handle all my routing and states, so I have to factor that into how I'm going to handle the desired behavior.
Help?
I worked on both those topics (deep state reactivation and parallel states) and integration into ui-router. Grab my github fork of ui-router and build using grunt. Then, mark your two tab states as parallel: true and deepStateRedirect: true.
Git repo: https://github.com/christopherthielen/ui-router
Example plunker: http://plnkr.co/edit/YhQyPV?p=preview
Discussion: https://github.com/angular-ui/ui-router/issues/894
I would just save the current state in a variable, then either dynamically change the link of the tab to whatever the last subview was.
For example, if the user is on /admin/billing, the Admin tab would link to admin/billing. When they leave that tab, the /admin tab remains the same. If you are using ui-router, you can do this with ui-srefs. You could also just manually check the variable when the state changes, and route the user there from the controller.

NGgrid not refreshing after update in modal window

User can update value for multiple rows in an nggrid using a modal window. After user confirms update and closes modal window, grid does not refresh. Navigating away from page and coming back indicates that the update took effect, but I want this to take effect right away, without having to use location.reload(). Any ideas?
If your modal is a directive I'm guessing (without having seen the code) that you need a $scope.$apply in the directive...

Resources