Подтвердить что ты не робот

Как передать многие значения в директиву Angularjs?

Я создаю многоразовый бит html через директиву. В html будет несколько переменных, которые я хочу передать из исходной области. Это делается легко, объявляя атрибуты в директиве, затем создавая область изоляции и захватывая их. Вопрос в том, есть ли лучший способ сделать это для большего числа переменных? Я подумал о том, чтобы передать объект, подобный {firstAttr: $scope.one, secondAttr: $scope.two...}, и выделить этот объект отдельно, чтобы получить каждую деталь. Это работает в первый раз, но двухсторонняя привязка данных не работает (даже используя "=" ).

Проблема связана с объектом, а не с каждой отдельной частью объекта. Могу ли я использовать функцию компиляции в директиве, чтобы добавить каждый из атрибутов к элементу или что-то еще? так:

<mydirective databinding="{one:'first one', two:'second one'}">

будет переведен в:

<mydirective one="first one" two="second one">

Таким образом, моя привязка данных будет работать, как и ожидалось, путем захвата атрибутов в директиве. Как мне пойти на выполнение этого проекта, или есть ли еще один способ полностью сделать это?

4b9b3361

Ответ 1

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

Решение 1

Если вам нужна только одна привязка данных, самым простым решением является использование области angular. $eval для строкового представления объекта внутри вашей директивы после интерполирования любых простых переменных сферы на нем с помощью {{}}. Строковое представление даже не должно быть допустимым JSON, так как вы заметите в примере ниже, я не включаю кавычки вокруг ключей объектов.

В представлении:

<div databinding="{one:'first', two:{{scopeVar}}, complex:[1,2, "Hi"]}"></div>

И в javascript:

app.directive('databinding', function () {
   return{
      link: function (scope, elm, attrs) {

        console.debug(scope.$eval(attrs['databinding']));

      }
   }
});

Решение 2

Еще одно одностороннее решение привязки данных - создать объект-объект внутри контроллера и передать его в директиву с помощью "@" (или даже "=" ):

В контроллере:

$scope.options = {one: "first, two: "second"};

В представлении:

<div databinding="options"></div>

И в javascript:

app.directive('databinding', function () {
   return{
      scope: {

        options: "@" //Can also use = here

      },
      link: function (scope, elm, attrs) {

        console.log(scope.options);

      }
   }
});

Решение 3

Если вам нужна двусторонняя привязка данных, вам в основном не повезло, так как нет элегантного способа сделать это. ОДНАКО, если вы находитесь на рынке хакерских решений, вы можете выполнить двустороннюю привязку данных с помощью метода, очень похожего на решение 2, но с изменением объекта option.

Вместо объявления объекта option, содержащего простые примитивные типы данных, такие как строки, создайте фиктивный объект внутри объекта option, который затем объявите переменные внутри. Таким образом, изменения в переменных области в вашем контроллере также будут реализованы внутри директивы, как показано через таймауты.

Контроллер:

$scope.someScopeVar = "Declared in controller"    

$scope.options = {
  dummy: {
     one: $scope.someScopeVar,
     two: "second"
  }
}

window.setTimeout(function(){

  $scope.someScopeVar = "Changed in controller";

}, 2000)

Вид:

<div databinding="options"></div>

Директива

app.directive('databinding', function () {
   return{
      scope: {
        options: "=" //You need to use = with this solution
      },
      link: function (scope, elm, attrs) {

        console.log(scope.options.dummy.one); //Outputs "Declared in controller"

        window.setTimeout(function(){

           console.log(scope.options.dummy.one) //Outputs "Changed in controller"

        }, 5000)

      }
   }
});

Этот метод работает, поскольку javascript передает объекты по ссылке, тогда как примитивы копируются. При вложении объекта в объект сохраняется привязка данных.

Ответ 2

Вы можете изменить область действия в директиве следующим образом

.('mydirective ', function(){

   var linker = function(scope, element){
        console.log(scope.one, scope.two);    
   }    
   return {
        link: linker,
        scope: {one:"=", two:"="}
   }    
});

Ответ 3

Вопрос в том, есть ли лучший способ сделать это для большего числа переменных?

Я так не думаю. Как вы уже выяснили, попытка передать их как один объект приводит к тому, что объект является привязкой к данным, а не отдельными частями.

Даже если вы могли бы получить что-то, работающее с компиляцией $, не было бы очевидно, чтобы другие люди читали ваш код, что происходит.

Другой вариант - либо не создавать область (scope: false, которая является директивой по умолчанию для директив), либо создать новую область с правами пользователя (scope: true), но потребовать, чтобы область вызова должна использовать определенные имена свойств области используйте директиву. Тогда вам не нужно указывать какие-либо атрибуты. Это делает директиву гораздо более ограничительной, но я думаю, что это ваш выбор: указать несколько атрибутов или потребовать определенные имена свойств области.