CodeGenius
CodeGenius

Reputation: 514

change directive when scope variable changes

I am using http request to get data from json file which I than use in controller.

    app.controller('mainCtrl', ['$scope', 'loaderService', function ($scope, loaderService) {
   //gets data from service 
        loaderService.getLoadedHtml().then(function (result) {
            $scope.fields = result.data;
        });
    }]);

I need to update directive when this $scope.fields change as

app.directive('dform', function () {
    return {
        scope: {
            action: '@',
            method: '@',
            html: '='
        },
        link: function (scope, elm, attrs) {
            var config = {
                "html": scope.fields
            };

            scope.$watch('fields', function (val) {
                elm.dform(config);
            });

            //console.log(config);
            //elm.dform(config);
        }
    };
})

and here is how I am using this directive

<div html="fields" dform></div>

But in my case when $scope.fields changes, i get scope as undefined in my directive $watch function.

Question:

How can I get the updated value for scope.fields in scope.$watch function?

Upvotes: 4

Views: 945

Answers (3)

Estus Flask
Estus Flask

Reputation: 222319

Usually for directives that should be as transparent as possible, no new scope is supposed be used. Having a new scope also prevents other directives from requesting a new scope on the same element.

If only one of the attributes is supposed to be dynamic, it is as simple as

scope: false,
link: function (scope, elm, attrs) {
    scope.$watch(function () { return scope[attrs.html] }, function (val) {
        if (val === undefined) return;

        var config = {
            action: attrs.action,
            method: attrs.method,
            html: val
        };

        elm.dform(config);
    });

}

Alternatively, bindToController can be used in more modern, future-proof fashion (depending on what happens with html, $scope.$watch can be further upgraded to self.$onChanges hook).

scope: true,
bindToController: {
    action: '@',
    method: '@',
    html: '='
},
controller: function ($scope, $element) {
    var self = this;

    $scope.$watch(function () { return self.html }, function (val) {
        if (val === undefined) return;

        var config = {
            action: attrs.action,
            method: attrs.method,
            html: val
        };

        $element.dform(config);
    });
}

Considering that html="fields", the code above will watch for fields scope property.

Upvotes: 1

tasseKATT
tasseKATT

Reputation: 38490

You need to give the directive access to fields by adding a binding for it:

scope: {
  action: '@',
  method: '@',
  html: '=',
  fields: '='
}

And HTML:

<dform fields="fields" ...

The value might be undefined the first time, then you don't want to call dform:

scope.$watch('fields', function(newValue, oldValue) {

  if (newValue === oldValue) return;

  var config = {
    "html": newValue
  };

  elm.dform(config);
});

Update

With this HTML:

<div html="fields" dform></div>

You just need to watch html instead, no need for $parent or adding fields as a binding:

scope.$watch('html', ...

Upvotes: 2

user6746249
user6746249

Reputation:

use $parent.fields instead of fields

Upvotes: 0

Related Questions