DiPix
DiPix

Reputation: 6083

How to pass object to directive through attribute in AngularJS?

I want to pass object (reference - two way binding) through ATTRIBUTE not by isolated scope. How can I do this? Because code bellow passing string instead of object:

HTML

<tr ng-form="rowForm" myDirective="{{row.data}}">

Directive

angular.module("app").directive("myDirective", function () {
    return {
        require: ["^form"],
        restrict: "A",
        link: function (scope, element, attrs, ctrls) {
            scope.$watch(function () {
                return attrs.myDirective;
            }, function (newValue, oldValue) {
            // .....

Upvotes: 3

Views: 17506

Answers (3)

maurycy
maurycy

Reputation: 8465

Directives can do two-way data binding without parsing or compile anything manually, sorry for not delivering the plunker but it's rebelius and won't save for me

JS

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.myObj = {name: 'Tibro', age: 255}
})
.directive('myDirective', function(){
  return {
    scope: {
      'myAttribute': '='
    },
    template: '{{myAttribute}}',
    link: function(scope){
      scope.myAttribute.age= 31
    }
  }
})

HTML

  <body ng-controller="MainCtrl">
    controller: {{myObj}} <br/>
    directive: <my-directive my-attribute="myObj"></my-directive>
  </body>

OUTPUT

controller: {"name":"Tibro","age":31} 
directive: {"name":"Tibro","age":31}

you can see from the output that passed object has been binded two-way and change made in directive is reflected on controller level

Upvotes: 5

Estus Flask
Estus Flask

Reputation: 222309

The result of {{ }} interpolation is a string. An object can't be passed like that.

Bindings are idiomatic here and thus preferable. The whole thing becomes messy when the directive is forced to use parent scope. However, it can be done by parsing scope properties manually with $parse:

  $scope.$watch(function () {
    var myDirectiveGetter = $parse($attrs.myDirective);
    return myDirectiveGetter($scope);
  }, ...);

This is a job for binding (< or =, depending on the case). If isolated scope isn't desirable, this can be done with inherited scope and bindToController:

scope: true,
bindToController: {
  myDirective: '<'
},
controllerAs: `vm`,
controller: function ($scope) {
  $scope.$watch('vm.myDirective', ...);
}

Notice that directive attribute is my-directive, not myDirective.

Upvotes: 2

George Kagan
George Kagan

Reputation: 6124

Couple of things:

  1. myDirective in the tr should be my-directive, as per Angular's conventions.
  2. {{row.data}} prints the variable, you need to pass it without the {{}} for it to go through as an object.

Upvotes: 0

Related Questions