2013-09-18 4 views
12

Если у меня есть директива AngularJS без шаблона, и я хочу, чтобы она установила свойство в текущей области, что это лучший способ сделать это?AngularJS Custom Directive Two Way Binding

Например, директива, которая подсчитывает нажатия кнопок:

<button twoway="counter">Click Me</button> 
<p>Click Count: {{ counter }}</p> 

С директивой, которая назначает количество кликов для выражения в атрибуте два пути:

.directive('twoway', [ 
'$parse', 
    function($parse) { 
    return { 
     scope: false, 
     link: function(scope, elem, attrs) { 
     elem.on('click', function() { 
      var current = scope.$eval(attrs.twoway) || 0; 
      $parse(attrs.twoway).assign(scope, ++current); 
      scope.$apply(); 
     }); 
     } 
    }; 
    } 
]) 

Есть ли лучший способ сделать это? Из того, что я прочитал, изолированный охват будет излишним, но мне нужен охват ребенка? И есть ли более чистый способ написать обратно переменную области видимости, определенную в атрибуте директивы, отличную от использования $parse. Я просто чувствую, что делаю это слишком сложно.

Full Plunker here.

+2

Этот вопрос, как представляется, не по теме, поскольку речь идет о проверке кода. – zsong

+1

Или архитектура кода. Я думаю, что это хороший вопрос. – dudewad

ответ

27

Почему изоляция размахивает? его очень полезно именно для такого рода вещи:

scope: { 
    "twoway": "=" // two way binding 
    }, 

Это довольно идиоматическое угловое решение этой проблемы, так это то, что я бы придерживаться.

+0

Doug T. Я ушел из [этого сообщения SO] (http://stackoverflow.com/questions/14914213/when-writing-a-directive-how-do-i-decide-if-a-need-no -new-scope-a-new-child-sc), но я, вероятно, понял только четверть этого. –

+22

Критическое дополнение к этому ответу состоит в том, что переменная, которую вы передаете в эту директиву, например, 'counter', ** должен ** быть объектом, например. 'obj.counter', иначе вы не получите правильную ссылку для обновления родительской области. – morloch

2

Вы можете определенно упростить это немного, как это без использования $parse

angular.module('directive-binding', []).directive('twoway', [function() { 
    return { 
     scope: false, 
     link: function (scope, elem, attrs) { 
      elem.on('click', function() { 
       scope[attrs.twoway] = scope[attrs.twoway] == null ? 1 : scope[attrs.twoway] + 1; 
       scope.$apply(); 
      }); 
     } 
    }; 
}]); 
+1

Это не работает, если вы используете «вложенный» объект в своей модели. Например, если я использовал «counter.val» вместо «counter», это не работает. [Вот Plunker] (http://plnkr.co/edit/AvTTgW?p=preview) - мои навыки JS не самые лучшие, поэтому я, возможно, что-то пропустил. –

+0

@DavidFaivre Вам необходимо инициализировать его в контроллере, например '$ scope.counter = {}; $ scope.counter.val = 0' – zsong

+0

, если вам интересно, см. [this] (http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key) при доступе к " вложенных "объектов по строкам. Это основная проблема с этим решением - вам придется писать какой-то парсер. Служба парсера $ или картирование вложенных областей обрабатывает это для нас в Угловом мире. –

0

Пользователь attrs.$set:

attrs.$set('twoway', attrs.twoway++); 

гляньте Атрибуты раздел http://docs.angularjs.org/guide/directive

+0

Это устанавливает _text_ атрибута, а не базовое значение, которое атрибут может указывать на модель. –

22

Я не буду удивлен, не один упомянул ng-model, директиву по умолчанию для выполнения привязки двух данных. Может быть, это не так хорошо известны, но функция связывания имеет четвертый параметр:

angular.module('directive-binding', []) 
    .directive('twoway', 
     function() { 
     return { 
      require: '?ngModel', 
      link: function(scope, elem, attrs, ngModel) { 
      elem.on('click', function() { 
       var counter = ngModel.$viewValue ? ngModel.$viewValue : 0 
       ngModel.$setViewValue(++counter); 
       scope.$apply(); 
      }); 
      } 
     }; 
     } 
    ); 

На ваш взгляд

<button twoway ng-model="counter">Click Me</button> 
<p>Click Count: {{ counter }}</p> 

Четвертый параметр является API для ngModelController, который имеет множество применений для обработки (разбор и форматирование, например) и обмен данными между директивой и областью действия.

Просьба обновить Plunker.

+0

Я надеялся смоделировать синтаксис директивы после чего-то вроде ngshow/nghide, который берет свойство модели непосредственно в его значении атрибута. Я высоко ценю реализацию с помощью ngModel, хотя - это то, что я еще не изучил до глубины души. –

+1

Затем перейдите для выделения области, см. Ответ Дуга. – jjperezaguinaga

1

Отличный способ применения двусторонней привязки - использовать директивные компоненты. Вот мое решение. Это позволяет использовать привязку ng-repeat и расширяемую привязку данных.

View Plunker

HTML

<body ng-controller='MainCtrl'> 
    Data: {{data}} 
    <hr> 
    <mydirective name='data[0]'></mydirective> 
    <hr> 
    <mydirective name='data[1]'></mydirective> 
</body> 

Контроллер

app.controller('MainCtrl', function($scope) { 
    $scope.data = []; 
    $scope.data[0] = 'Marco'; 
    $scope.data[1] = 'Billy'; 
}); 

Директива

app.directive("mydirective", function(){ 
    return { 
     restrict: "EA", 
     scope: {name: '='}, 
     template: "<div>Your name is : {{name}}</div>"+ 
     "Change your name : <input type='text' ng-model='name' />" 
    }; 
}); 

В случае счетчика это может быть сделано с использованием того же метода.

-1

Изменить шаблон:

<button twoway bind="counter">Click Me</button> 
<p>Click Count: {{ counter.val }}</p> 

и директива:

.directive('twoway', 
    function() { 
     return { 
      scope: { 
       localValue: '=?bind' 
      }, 
      link: function(scope, elem, attrs) { 
       scope.localValue = { 
        val: 0 
       }; 
       elem.on('click', function() { 
        scope.localValue.val = scope.localValue.val + 1; 
        scope.$apply(); 
       }); 
      } 
     }; 
    } 
); 
+1

Можете ли вы объяснить, как это ответ на вопрос? – soundslikeodd

+0

Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и/или почему оно решает проблему, улучшит долгосрочную ценность ответа. –

Смежные вопросы