Директива AngularJS Двусторонняя привязка данных не работает при наблюдении булевых

У меня есть двусторонняя привязка данных, которая не изменяет значение переменной, отправленной в директиву.

Моя директива наблюдает за триггером и фокусируется на элементе associates (на основе кода, найденного здесь в SO):

app.directive('focusMe', function ($timeout) {
  return {
    scope: {
      trigger: '=focusMe'
    },
    link: function (scope, element, attrs) {
      scope.$watch('trigger', function(value) {
        console.log("directive value: " + value);
        console.log("directive start: " + scope.trigger);
        if (value === true) {
          $timeout(function () {
            element[0].focus();
            scope.trigger = false;
            console.log("directive end: " + scope.trigger);
          });
        }
      });
    }
  }
});

В HTML я называю это следующим образом:

<input type="text" ng-model="item.value" focus-me="focusInput" />

Когда я запускаю его в первый раз, он работает, потому что переменная focusInput переключает свое значение. Но focusInput в области контроллеров (вне директивы) не возвращается к false, когда директива завершается.

Этот переключатель обратно в false должен произойти, когда я вызываю scope.trigger = false, предполагая, что я понимаю, что должно произойти.

Что не хватает, что приведет к тому, что двусторонняя привязка не приведет значение обратно к переменной, переданной в директиву?

ОБНОВЛЕНИЕ 01:

Для публикации вопроса я удалил небольшой бит кода. HTML выглядит так:

<input type="text" ng-model="item.value" focus-me="focusInput" ng-if="item.condition != 'matches' && item.condition != 'does not match'" />

Если поля input скрываются, а затем повторно отображаются (на основе ng-if), директива будет правильно давать фокус при первом изменении focusInput. После этого он перестанет работать снова, если не будет повторяться процесс hide/show.

Ответы

Ответ 1

Проблема, с которой вы сталкиваетесь, является общей проблемой при работе с примитивными значениями (boolean, int и т.д.) в пределах областей.

Я настоятельно рекомендую прочитать статью Понимание областей. (короткий ответ: примитивы изменяются в изолированной области действия директивы и не ищут цепочку для родительской области, то есть области вашего контроллера).

Что касается того, как решить вашу ситуацию, я предлагаю использовать точечную нотацию и хранить ваш примитив внутри объекта и привязать этот объект к вашей директиве:

scope: {
   triggerObj: '=focusMe'
},

И убедитесь, что ваши триггерные ссылки в директиве теперь scope.triggerObj.trigger.

И у вашего контроллера есть:

$scope.triggerObj = {};
$scope.triggerObj.trigger = true; //or false, what have you

Наличие объекта гарантирует, что двусторонняя привязка будет работать. И прочитайте статью выше, когда у вас есть время:)

Ответ 2

Директива создает область действия. когда вы передаете параметр в область, объект передается по ссылке и boolean (и number, string...), переданный по значению.

Например:

function changeToFalse(bool) {
    bool= false;
    console.log(bool);  // false
}


function changeObjToFalse(obj) {
    obj.bool= false;
    console.log(obj.bool);  // false
}

var obj = {bool : true};

changeToFalse(obj.bool);
console.log(obj.bool);  // true
changeObjToFalse(obj);
console.log(obj.bool); // false

См. также тот же вопрос - двусторонняя привязка, не работающая с ng-repeat.