2013-06-06 2 views
2

Я пытаюсь написать общую директиву для своих угловых приложений, которая превращает поле ввода в jquery timepicker.Угловая привязка данных директивы не работает должным образом

У меня есть два поля ввода: fromTime и toTime, и я хочу обновить toTime, когда изменяется значение fromTime.

Мой код выглядит следующим образом:

HTML

<input type="text" 
     time-picker="{ timeFormat: 'H:i'}" 
     class="input-block-level" 
     name="fromTime" 
     ng-model="filter.fromTime" 
     ng-change="update()" 
/> 

<input type="text" 
     time-picker="{ timeFormat: 'H:i'}" 
     class="input-block-level" 
     name="toTime" 
     ng-model="filter.toTime" 
     ng-change="update()" 
/> 

ДИРЕКТИВА

sharedServices.directive('TimePicker', function() { 
return { 
    restrict: 'A', 
    scope: { 
     time: "=ngModel" 
    }, 
    link: function(scope, element, attrs) { 
        //Initialize the timepicker 
     $(element).timepicker(scope.$eval(attrs.TimePicker)); 
        //watch for changes 
     scope.$watch('time', function(stuff) { 
      console.log('some change', stuff); 
     }); 
    } 
}; 
}); 

sharedServices ВКЛЮЧЕНЫ

var roomsApp = angular.module("roomsApp", ["ngResource",'ui', 'sharedServices','ui.bootstrap']).config(function($routeProvider) { ... 

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

* Обновление http://plnkr.co/edit/t3BzShezEdh29ZAlI8ZI?p=preview Это демонстрирует мою проблему. Ничто не консольная регистрируется при изменении даты

+0

Покажите нам код, в котором включена директива. Я вижу несколько вещей, которые действительно странные. – TheHippo

+0

@ TheHippo, сделано. Инициализируются директивные нагрузки и истечет время. Но привязка между областью действия и директивой работает некорректно. – Bjarki

+0

Пожалуйста, продолжайте использовать ngModelController, но не как опцию вашей изолированной области, установите ее как необходимый контроллер, введенный в качестве четвертого аргумента вашей функции linkibg, перегружая свой метод $ render, используя свой $ viewValue и используя его $ setViewValue на вашем Изменения виджета пользовательского интерфейса в сочетании с $ apply вызвали область. – lib3d

ответ

6

Чтобы устранить эту проблему

Вы должны будете слушать изменения в поле ввода и обновления scope.time.

Первое изменение, которое я сделал, должно было включать в себя Угловое после jQuery, таким образом параметр element будет объектом jQuery.

Затем послушать событие изменения и обновление scope.time.Оберните звонок в scope.$apply, чтобы сообщить Angular, что что-то изменилось.

element.on('change', function() { 
    scope.$apply(function() { 
     scope.time = element.datepicker('getDate'); 
    }); 
}); 

Plunker

Альтернативный подход

лично при написании директив, которые применяются на входных элементах, которые я хочу, чтобы позволить пользователю использовать ngModel директиву, чтобы сохранить данные в синхронизации, так как это известное соглашение. Используя ngModel, вы также можете (необязательно) использовать его контроллер для добавления пользовательской проверки или другой логики, например. парсеров/форматировщиков (в этом случае не требуется).

С помощью сервиса $parse мы можем считывать/записывать данные обратно в поле ngModel.

Я также изменил так, чтобы опции datetime могли быть переданы при необходимости.

Наконец-то я перевел первый вызов функции компиляции datetime(), так как это место должно быть выполнено с помощью DOM-манипуляции.

.directive("datetime", ['$parse', function($parse) { 
    return { 
     require: '?ngModel', 
     restrict: 'A', 
     compile: function (element, attrs) { 
     var options = $parse(attrs.datetime)() || {}; 
     console.log('Passed options:', options); 

     element.datepicker(options); 

     // Return the link function 
     return function (scope, element, attrs, ngModel) { 
      var getter, setter; 

      // If the ngModel directive is used, then set the initial value and keep it in sync 
      if (ngModel) { 
      getter = $parse(attrs.ngModel); 
      setter = getter.assign; 

      console.log('ngModel directive used, setting initial value') 
      element.datepicker("setDate", getter(scope)); 

      scope.$watch(attrs.ngModel, function(val, prev) { 
       console.log('ngModel changed from', prev, 'to', val); 
      }); 

      element.on('change', function() { 
       console.log('change'); 
       var newValue = element.datepicker('getDate'); 
       scope.$apply(function() { 
       setter(scope, newValue); 
       }); 
      }); 
      } 
     }; 
     } 
    }; 
}]) 

И директива используется так:

<input type="text" datetime="{showButtonPanel: true}" ng-model="parentTime" /> 

Plunker

+0

Это сработало отлично. Спасибо огромное ! – Bjarki

+0

Я не понимаю, почему директива ng-model перестала работать в первую очередь. Я в ситуации, когда он работает (связывает входное значение с моделью видимости), пока я не добавлю настраиваемую директиву к элементу. Тогда привязка больше не происходит. Я просто ожидал, что они упадут. – BigOmega

0

Update: Вот очень рудиментарные implementaion с помощью Jquery DatePicker - http://plnkr.co/edit/4JZIWo6mJqg59F5o7xdh?p=preview

angular 
.module("demo", []) 
.directive("test", function() { 
    return { 
     restrict: 'A', 
     scope: { 
      time: "=" 
     }, 
     link: function(scope, element, attrs) { 
     console.log("scope.time:" + scope.time); 
     $(element).datepicker(); 
     $(element).datepicker("setDate", scope.time); 
     } 
    }; 
}) 
.controller("demoCtl", function($scope){ 
    $scope.parentTime = new Date(); 
}); 

Посмотрите angular-ui calendar module. Если вы не хотите его использовать, вы можете посмотреть их код, чтобы помочь вам.


Кроме того, способ настройки области видится странным. Я думаю, вы хотите привязать свойство директивы time к свойству, управляемому родительской областью директивы, а не к ng-модели.

попробовать этот

return { 
    restrict: 'A', 
    scope: { 
     time: "=" 
    }, 
    link: function(scope, element, attrs) { 
        //Initialize the timepicker 
     $(element).timepicker(scope.$eval(attrs.TimePicker)); 
        //watch for changes 
     scope.$watch('time', function(stuff) { 
      console.log('some change', stuff); 
     }); 
    } 
}; 

и использовать его

<input type="text" 
     time-picker="{ timeFormat: 'H:i'}" 
     class="input-block-level" 
     name="toTime" 
     time="filter.toTime" 
     ng-change="update()" 
/> 

также вам не нужно обернуть attrs.TimePicker в $scope.eval.

+1

Используя только «=», модель «время» не определена:/и не использует $ scope.eval, кажется, игнорирует опции – Bjarki

+0

обновил мой ответ с рабочей демонстрацией – Jason

+0

, чтобы проверить это: http://plnkr.co/edit/ ? t3BzShezEdh29ZAlI8ZI р = предварительный просмотр – Bjarki

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