0

While transitioning an existing angular site, I encountered an annoying problem. The initial symptom was that a certain controller was not running it's initialize function immediately following the login. I logged and I tracked, and eventually I realized it was a design flaw of the page. Essentially, index.html contains a <header>, <ng-view>, and <footer>. There are a couple of ng-if attributes that live in the header that I want to evaluate after the login, but since the view is the only thing that is reloaded, it was not reinitializing the header controller, and thus not updating the ng-if values.

Then I was reminded of ngInclude, which seems like the perfect solution, until I got it hooked up and realize that doesn't work either. It loads the template the first time, and doesn't reinitialize when the view changes. So then I got the bright idea of passing the HeaderController to another controller or service, and controlling this one stubborn boolean value through a proxy of sorts. That also didn't work. Then I tried putting a function and a boolean into another service, and mirroring that property in the header controller, but thus far I have not gotten this working.

I have done plenty of research about multiple views in the index, and so far I hear a lot about this ui-router, but I'm still not convinced that is the way I want to go. It does not seem to be a simple solution. I have not tried putting the ng-include into the templates yet either, because then I feel like that is going back in time to when we had to update 100 pages every time we changed the menu.

I lost a whole day to this. If anyone could tell me how to trigger the evaluation of this one property in my header controller which I would like to live outside the other templates, please let me know!

2
  • Is it a routing issue like in this thread stackoverflow.com/questions/18914183/… ? Commented Apr 1, 2016 at 17:14
  • @ralfhtp the header does not get its own route Commented Apr 1, 2016 at 17:19

1 Answer 1

1

Ok so you need to know in your HeaderController when the view has reloaded. There's a number of ways of doing this but the easier and maybe the more correct in this particular case is with an event.

So when you are refreshing the view you just do this, let's say you need the new value of ob1 and ob2 variables.

// ViewController
$rootScope.$emit('viewRefresh', {ob1: 'newvalue1', ob2: 'newvalue2'});

And in your HeaderController you need to listen for that event, and set on your $scope the new values for those attrs (if you're not using controller as syntax).

// HeaderController
$rootScope.$on('viewRefresh', function onRefresh(event, data) {
    $scope.ob1 = data.ob1;
    $scope.ob2 = data.ob2;
})

Another Solution Sharing a Promise through a Service (using $q)

function HeaderService($q) {
    var defer = $q.defer();
    return {
        getPromise: function() {return defer.promise},
        notify: function(data) {defer.notify(data)}
    }
}

function HeaderController(HeaderService) {
    var vm = this;
    HeaderService.getPromise().then(function(data) {
        vm.ob1 = data.ob1;
        vm.ob2 = data.ob2;
    })
}


function ViewController(HeaderService) {
    var data =  {ob1: 'newvalue1', ob2: 'newvalue2'};
    HeaderService.notify(data)
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for the answer. I am indeed using controllerAs syntax, and I generally try to avoid doing too much with $rootScope. If this was your website and you had all the time in the world, is that how you would fix this? If not, would you share your ideal solution here? @Bolza
Also, for this solution, are you recommending I put this into all of my view templates?
Honestly if you don't have many cases like this, i believe messing with the rootScope is fine. Especially when it's about very important components used everywhere in the website like the Header. Another solution could be creating a service that returns a promise, i'm updating the answer with this.
You might be right about it being safe to update $rootScope for a menu that is fundamentally global, but for the sake of exploring all options, what do you think about the idea of using a directive? I have not written a lot of directives, but I know it can be associated with a template and is intended for DOM manipulation, which is what this problem represents. @Bolza
Even if you use a directive you'll still need a way to comunicate between some controller that updates the data and your directive that shows those data. What do you think of using a promise and a service as i suggested in the second part of the answer?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.