Reusing previously instantiated templates with ng-include

巧了我就是萌 提交于 2019-12-13 17:32:51

问题


I have a need for a <select> on a form to control the remaining available inputs. This is achieved easily with angular by binding the <select> to the src of an ng-include.

The problem is each time the user changes the selected value (and hence the src template), angular compiles the template from scratch and attaches a new scope. This has the effect of wiping all the input data each time. The user expects if they change back to a previously selected option, all the field data they previously entered will still be there.

Is there any built in way to achieve the desired behaviour? Ideally an option so that the ng-include will re-use a previously compiled template and associated scope?

One workaround is to ng-include all the templates, and use ng-show to only display the current one. This seems heavy though, there is a lot of DOM elements on the page unnecessarily. (Especially for my use-case where there will be about ~20 different templates, and this whole <select> element and dynamic template control may be repeated on a single page up to 40 times.)

Here is a jsFiddle. The desired outcome is the counter on template 1 is persisted when changing the dropdown to template 2 and back to 1.


回答1:


I found this question interesting. Short of putting the model in a service (which is probably the correct way), I don't think there is a built in way to cache templates with ng-include without using ng-repeat, as demonstrated in this fiddle.

<div ng-controller="Ctrl">
    <select ng-model="template" ng-options="t.name for t in templates">
     <option value="">(blank)</option>
    </select>
    url of the template: <tt>{{template.url}}</tt>
    <hr/>
    <div ng-repeat="t in templates" ng-include="t.url" ng-show="template.name == t.name">
     </div>
  </div>

As you point out, the downside of this solution is you end up with a lot of elements in the DOM.

For fun, I wrote a version of ng-include that caches the template element and reuses it. You still end up potentially creating just as many DOM nodes in the worst case, but since they are created only on-demand, and since only one is ever in the DOM at any given time, it should remain fairly efficient from an angular perspective.

Here is the fiddle for this directive.

.directive('cacheInclude', function ($compile, $http, $templateCache) {
    return {
        link: function (scope, element, attrs, ctrl) {
            var cache = {};
            var currentElement = element;
            var replaceCurrent = function(cacheEntry) {

                currentElement.replaceWith(cacheEntry);
                currentElement = cacheEntry;
            };
            scope.$watch(function(){
                return scope.$eval(attrs.src);
            }, function () {
                var src = scope.$eval(attrs.src);

                if (!cache[src]) {
                    $http.get(src, {cache: $templateCache}).then(function (result) {


                        cache[src] = $compile(result.data.trim())(scope.$new());
                        replaceCurrent(cache[src]);
                    });
                } else {

                    replaceCurrent(cache[src]);
                }
            });
        }
    }
})

It's not "built in", but I think it is a good middle ground solution. Note, the directive is "for example only" and still requires error handling, etc.



来源:https://stackoverflow.com/questions/28654061/reusing-previously-instantiated-templates-with-ng-include

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!