Kiwi
Kiwi

Reputation: 2773

Angular directive binding

I'm trying to have Two-Way binding on a directive.

I can't use the scope on the directive (multiple directives on element), so I'll have to do it in the compile(){...} function

This is a simplified version of the directive so far:

.directive('myDialog', function() {
      return {
        restrict: 'E',
        templateUrl: 'my-dialog.html',
        compile: function(tElement, tAttrs, transclude) {
          return function($scope, $element, $attributes) {
            $scope.label = $scope.$eval($attributes.label);

            // when I set the label on something this should update the parent
            $scope.label = "test";
          }
        }
      };

So how can I make it that when I change the lable in my directive it updates the value in the main application, and visa versa

Plunker for testing: http://plnkr.co/edit/lARCrGD5FsnOWQZrahIl?p=preview

UPDATE: here is the actual setup with all the logic for what I'm trying to archieve: http://codepen.io/cskiwi/pen/eJryqK?editors=1010

On line 101 i want to set the testing var on true, later one I'm also going to set to testing var on false outside that directive

UPDATE2: Got something, that is maybe something to lookinto:

  return {
        restrict: "A",
        require: ["^mdChips", "^chipBar"],
        controller: "chipBarController",
        controllerAs: "chipBarController",
        bindToController: {
            activated: "="
        },
        // rest of the code

this is allowing to set the activated var to true from in the directive; but now I can't set the value from my appCtrl back to false

Upvotes: 0

Views: 158

Answers (3)

Walfrat
Walfrat

Reputation: 5353

I agree with coments saying that you have probably a design problem but 'ill give you a way to do what you want.

Use ng-model directive and controller then with that you can read/watch for change/change the value :)

See tutorial here : https://www.nadeau.tv/using-ngmodelcontroller-with-custom-directives/

EDIT : well if you can use proper binding i have a quite dirty and tricky way of doing it : Based on this documentation : https://docs.angularjs.org/api/ng/function/angular.element

Add an attribute which will contains the field path as a string in controller scope (a.b.c if it's in $scope.a.b.c) like this

Get the parent element of your directive with angular.element() and get his scope with the scope method (in the documentation). Then call the $eval method if this scope like this to read theScope.$eval(attrs.fieldsPath); and with the $eval you should be able to update values too with theScope.$eval(attrs.fieldsPath+='myValue'). If it doesn't work you'd have to split your string with '.' and navigate through the scope object to write on the right field.

var value = $scope;
var tab  = attrs.fieldPath.split('.');
for(i = 0; i < tab.length && value; i++){
    value = value[tab[i]];
}

Upvotes: 0

Kiwi
Kiwi

Reputation: 2773

The update2 was actually fixing the issue.

    controllerAs: "chipBarController",
    bindToController: {
        activated: "="
    },

did everything it needed,

had just a typo in my code

Thanks Everyone who helped, especially @Claies

Upvotes: 0

AlainIb
AlainIb

Reputation: 4728

her is a working plunker with data binding http://plnkr.co/edit/qtfEPfbNTZHHUEBhGYye?p=preview

there is a lot of detailled reading over the net

http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope

http://www.bennadel.com/blog/2726-isolate-scope-two-way-data-binding-is-eventually-consistent-in-angularjs.htm ...


You should create a scope variable for your directive to let the directive know which variable to bind one

HTML

  <div ng-controller="Controller">
    {{email}} &lt;== should become test on launch

    <my-dialog email="email"></my-dialog>

    <button ng-click="click()">click</button>  &lt;== should turn both in tst
  </div>

template my-dialog.html

<div class="alert">
      email is :- {{email}}!
</div>

JS

  angular.module('docsTransclusionExample', [])
    .controller('Controller', ['$scope', function($scope) {
      $scope.email = '[email protected]';

      $scope.click = function(){
        $scope.email = "tst";
      }
  }])
  .directive('myDialog', function() {
      return {
        restrict: 'E',
        scope : { // this create an isolated scope
           email:'='   // the email attribute is binded two way with '=', there is also '@' and '&'
        },
        templateUrl: 'my-dialog.html'

      };
    });

Upvotes: 1

Related Questions