Force view to refresh from controller

4,955 views
Skip to first unread message

Jim Lavin

unread,
Feb 5, 2013, 12:41:40 PM2/5/13
to ang...@googlegroups.com
I've got several views and controllers that get included in my app's chrome via ng:include so my page looks something like below:

<body>
    <div ng-include src="'/scripts/olo/siteheadernavigation/siteheadernavigation.html'" class="wrapper clearfix"></div>
    <div ng-view></div>
    <div ng-include src="'/scripts/olo/sitefooternavigation/sitefooternavigation.html'" class="wrapper clearfix"></div>
</body>

And each of my views have a directive in the html markup that pulls a localized string in to provide the prompts and labels in a language specified by the user. Such that my html is structured as that shown below in all of my partials:

<span data-i18n="WELCOME_LABEL">Welcome</span>

I have as service that is responsible for retrieving the localized strings from a service on the server, which is used in turn by the directive to get the localized text that is then used to update the text on the element. The directive source is given below:

Application.Directives.directive('i18n', ['localize', function (localize) {
    return {
        restrict: "EAC",
        link: function (scope, elm, attrs) {
            attrs.$observe('i18n', function (value) {
                var values = value.split('|');
                if (values.length >= 1) {
                    // construct the tag to insert into the element
                    var tag = localize.getLocalizedString(values[0]);
                    // update the element only if data was returned
                    if ((tag !== null) && (tag !== undefined) && (tag !== '')) {
                        // insert the text into the element
                        elm.text(tag);
                    } else {
                        // use the passed value if nothing was returned
                        elm.text(value);
                    };
                }
            });
        }
    };
}]);

Now my issue is that when ever the service reloads the localized string resources I want to broadcast a message to all of the controllers and have them re-draw their views, which in turn should cause the directives to be re-evaluated, which grabs the updated string and change the element's text to the new string.

The only way I can make this happen is to force a reload on the $route service, but that only causes the views that are in the ng-view to be updated and what I want is all views to be updated. I can do this by moving the header and footers into the partials so that my page looks like below:

<body>
    <div ng-view></div>
</body>

But then the partials have to include the header and footers:

<div ng-include src="'/scripts/olo/siteheadernavigation/siteheadernavigation.html'" class="wrapper clearfix"></div>
<div>
... view content here ...
</div>
<div ng-include src="'/scripts/olo/sitefooternavigation/sitefooternavigation.html'" class="wrapper clearfix"></div>

This seems like the wrong thing to be doing and it causes a lot of bloat in the partials and causes a lot of extra service calls to be made since the $route.reload() seems to invalidate everything

Is there something I can call from within a controller or directive to force a redraw of the HTML so the directives get updated with the new resource strings?

If you want to see the code you can look at the full solution out at Github - https://github.com/lavinjj/angularjs-localizationservice

Thanks



Florian Orben

unread,
Feb 5, 2013, 12:57:47 PM2/5/13
to ang...@googlegroups.com
Well you could trigger a $rootScope.$broadcast('lang-changed') in your service and listen for that event in your directive, causing the directive to change the text on $rootScope.$on('lang-changed').
That way you wouldn't need to refresh the whole view, but only the directives.

Florian Orben

unread,
Feb 5, 2013, 1:00:03 PM2/5/13
to ang...@googlegroups.com
... or inject the service into the directive, and $watch for changes on something like selectedLanguage which is being exposed by the service..
scope.$watch('i18nService.selectedLanguage', function() {
  //translate elem.text
});

Jim Lavin

unread,
Feb 5, 2013, 1:38:55 PM2/5/13
to ang...@googlegroups.com
Thanks I'll try both to see which works best.

Jim Lavin

unread,
Feb 5, 2013, 1:51:24 PM2/5/13
to ang...@googlegroups.com
Looks like adding a scope.$on solved the issue. My new directive is below:

Application.Directives.directive('i18n', ['localize', function(localize){
    var i18nDirective = {
        restrict:"EAC",
        updateText:function(elm, token){
            var values = token.split('|');
            if (values.length >= 1) {
                // construct the tag to insert into the element
                var tag = localize.getLocalizedString(values[0]);
                // update the element only if data was returned
                if ((tag !== null) && (tag !== undefined) && (tag !== '')) {
                    if (values.length > 1) {
                        for (var index = 1; index < values.length; index++) {
                            var target = '{' + (index - 1) + '}';
                            tag = tag.replace(target, values[index]);
                        }
                    }
                    // insert the text into the element
                    elm.text(tag);
                };
            }
        },

        link:function (scope, elm, attrs) {
            scope.$on('localizeResourcesUpdates', function() {
                i18nDirective.updateText(elm, attrs.i18n);
            });

            attrs.$observe('i18n', function (value) {
                i18nDirective.updateText(elm, attrs.i18n);
            });
        }
    };

    return i18nDirective;
}]);

Now when I switch languages everything updates without forcing a refresh of anything.

Thanks for the suggestion!
Reply all
Reply to author
Forward
0 new messages