4

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?

0

3 Answers 3

2

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', ...
Sign up to request clarification or add additional context in comments.

1 Comment

i don't want to create field as a new attribute here. I updated my question for better understanding.
1

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.

Comments

0

use $parent.fields instead of fields

7 Comments

@Umar Using $parent in a directive with isolated scope is antipattern.
@estus Thank you for the suggestion. Yes its against pattern, but I am in situation where I cannot use any workaround than this.
@Umar See the other answer, that's the correct one. It isn't obvious from your question why it isn't applicable here.
@estus Actually it is a jquery plugin. Here is it's full demonstration. stackoverflow.com/questions/41323138/… I just need fields. so html is extra here for me.
@Umar In this case I would suggest to use bindToController instead of isolated scope (like it is shown here stackoverflow.com/a/31415287/3731501). It allows to maintain proper scope hierarchy while still having bindings.
|

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.