Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: Proper scope binding when dynamically compiling a directive template

Given

  • directive D1 applied to an element E
  • directive D1 is passed a template that contains directive D2
  • directive D2 is subscribed to ngModel updates
  • directive D1 compiles template with directive D2
  • directives D1 and D2 are considered to be independent of each other
  • directives D1 and D2 have isolated scopes
  • (directive D1 might be detached from the DOM, but kept in memory)

Objective

  • make directive D2 react to scope changes of element E with applied D1 to it

index.html

<div ng-app="myApp" ng-controller="MainCtrl">
<label>
    <u>model: </u>
    <input type="text" ng-model="someValue" outer="tmpl.html"/>
    <hr/>
</label>

<script type="text/ng-template" id="tmpl.html">
    <inner test="123"></inner>
</script>

<script src="angular.js"></script>


app.js

(function (ng) {

var app = ng.module('myApp', []);

app.controller('MainCtrl', [
    '$scope',
    function ($scope) {
        $scope.someValue = 'Hello, World!';
    }
])
// directive D2
.directive('inner', function () {
    return {
        restrict: 'AE',
        replace: true,
        template: '<p>{{model || "N/A"}}</p>',
        scope: { model: '=ngModel' },
        link: function (scope, element, attrs) {
            scope.$watch('model', function (newValue, oldValue) {
                if (!ng.isDefined(oldValue) && !ng.isDefined(newValue)) {
                  return;
                }
                // do stuff...
            });
        }
    };
})
// directive D1
.directive('outer', [
    '$templateCache',
    '$compile',
    function ($templateCache, $compile) {
        return {
            restrict: 'AE',
            scope: {},
            link: function (scope, element, attrs) {
                var template = $templateCache.get(attrs.outer);
                var compiled = $compile(template)(scope);
                element.parent().append(compiled);
            }
      };
    }
]);

})(angular);

Fiddle

An overly simplified version is here: http://jsfiddle.net/Nscp8/12/

Example

D1 is a popover widget that can be configured to insert HTML as its contents. D2 is a QR-code widget that watches the model and updates on change.

Problem

The ngModel binding is not done properly and I don't get updates from it. What am I doing wrong here?

like image 381
John Doe Avatar asked Oct 20 '22 11:10

John Doe


1 Answers

scope: { model: '=ngModel' },

This binds the property model to the property defined in the attribute ng-model of the inner element, since you use the directive in form of an element. Your inner element does not have such an attribute.

But even if it had, the second problem would be that the parent scope of inner is the scope of outer, which is an isolate scope as well. someValue is defined in the controller´s scope, so inner has no chance to directly establish a binding with someValue, regardless of the type of binding you choose.

The solution depends on your specific needs. See this fiddle for one possible solution.

like image 170
a better oliver Avatar answered Oct 23 '22 06:10

a better oliver