Використання angularjs-фільтра у вхідному елементі


74

Сподіваюся, я не пропустив нічого очевидного в доко, якщо є, впевнений, хтось допоможе.

Я використовую asp.net webapi для повернення DTO з полями дати. Вони серіалізовані за допомогою JSON.Net (у форматі '2013-03-11T12: 37: 38.693').

Я хотів би використовувати фільтр, але в елементі INPUT це можливо чи слід створити новий фільтр або директиву для цього?

// this just displays the text value
<input ui-datetime type="text" data-ng-model="entity.date" /> 
// this doesn't work at all
<input ui-datetime type="text" data-ng-model="{{entity.date|date:'dd/MM/yyyy HH:mm:ss a'}}" /> 
// this works fine
{{entity.date|date:'dd/MM/yyyy HH:mm:ss a'}}

Чи є якийсь ярлик, якого я не маю?

Відповіді:


131

Коротше кажучи: якщо ви хочете, щоб ваші дані мали різне представлення у поданні та в моделі, вам знадобиться директива , яку ви можете сприймати як двосторонній фільтр .

Ваша директива буде виглядати приблизно так

angular.module('myApp').directive('myDirective', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModelController) {
      ngModelController.$parsers.push(function(data) {
        //convert data from view format to model format
        return data; //converted
      });

      ngModelController.$formatters.push(function(data) {
        //convert data from model format to view format
        return data; //converted
      });
    }
  }
});

HTML:

<input my-directive type="text" data-ng-model="entity.date" /> 

Ось робочий приклад jsFiddle .


5
Виглядає добре, але як би ви його застосували? Зокрема, як вказати фільтр для форматування?
Пол Тейлор

@PaulTaylor обмежує цю директиву лише `` атрибутом '' і використовує цей атрибут у полі введення (подібно до того, як ви пишете <input ng-model="foo">.
Aditya MP

Також перегляньте цю відповідь для більш повного прикладу.
Aditya MP

Робочий приклад на JSFiddle?
ViniciusPires

Дякую! Єдиного, чого не вистачало вашому прикладу для мого рішення, - це спостерігати за зміною моделі та повторно запускати програму форматування. Я не розумів, як я міг цього легко досягти за допомогою AngularJS, мені довелося змусити оновити елемент:scope.$watch(attrs.ngModel, function(value){ element.val( $filter('number')(value, 0) ); });
ViniciusPires

20

Наявність різних значень у полі введення та у вашій моделі суперечить самій природі ng-моделі. Тому я пропоную вам скористатися найпростішим підходом і застосувати фільтр всередині контролера, використовуючи окрему змінну для відформатованої дати та залучаючи спостерігачів для синхронізації відформатованих та оригінальних дат:

HTML:

<input ui-datetime type="text" data-ng-model="formattedDate" />

JS:

app.controller('AppController', function($scope, $filter){

  $scope.$watch('entity.date', function(unformattedDate){
    $scope.formattedDate = $filter('date')(unformattedDate, 'dd/MM/yyyy HH:mm:ss a');
  });

  $scope.$watch('formattedDate', function(formattedDate){
    $scope.entity.date = $filter('date')(formattedDate, 'yyy/MM/dd');
  });

  $scope.entity = {date: '2012/12/28'};

});

6
Я вважаю, що створення нової директиви для виконання вимог є більш чистим рішенням тут. Якщо я правильно зрозумів проблему OP.
голографічний принцип

Ти маєш рацію. Це чистіше. Я просто хотів дати можливість @leon, на випадок, якщо він / вона ще не дуже влаштовує власні директиви.
Стюі

Дякую, хлопці, обидві відповіді вдячні, оскільки чудово навчитися альтернативним методам.
Леон

3
-1, два змінних + перегляд - це пекло підтримки. Уявіть собі область із десятками змінних (страхові калькулятори тощо)
Валентин Васильєв

16

Якщо на вводі відображаються лише дані

Якщо вам насправді потрібні дані, щоб просто відобразити деяку інформацію, і це якийсь інший елемент, який змінюється модель Angular, ви можете зробити простіші зміни.

Замість того , щоб писати нову директиву просто НЕ ВИКОРИСТОВУВАТИng-model і використовувати хороший, старийvalue .

Отже, замість:

<input data-ng-model={{entity.date|date:'dd/MM/yyyy HH:mm:ss'}}" /> 

Це буде робити:

<input value="{{entity.date|date:'dd/MM/yyyy HH:mm:ss'}}" /> 

І працює як шарм :)


3

Повний приклад форматування чисел, вставляючи пробіли кожні 3 символи, починаючи з кінця:

'use strict'
String::reverse = ->
  @split('').reverse().join('')

app = angular.module('app', [])
app.directive 'intersperse', ->
  require: 'ngModel'
  link: (scope, element, attrs, modelCtrl) ->
    modelCtrl.$formatters.push (input) ->
      return unless input?
      input = input.toString()
      input.reverse().replace(/(.{3})/g, '$1 ').reverse()
    modelCtrl.$parsers.push (input) ->
      return unless input?
      input.replace(/\s/g, '')

Використання:

<input ng-model="price" intersperse/>

Приклад Plunkr: http://plnkr.co/edit/qo0h9z


Що саме робить синтаксичні аналізатори modelCtrl. $ (Або форматування) .push?
Вінсент

1
@Vincent, він додає функцію до масиву форматерів, яка викликається, коли потрібно відобразити значення з моделі. Подумайте про масив $ formatters як про конвеєр, заповнений функціями, де кожна функція викликається, а результат передається далі через конвеєр. Після виклику всіх функцій відображається кінцевий результат. Синтаксичний аналізатор $ - подібна річ, але для написання для моделювання.
Валентин Васильєв

Я не думаю, що це насправді працює, у вас є плункер або подібний?
mattcole

1
Приємно! Єдина проблема полягає в тому, що він додає пробіл перед числом будь-якої довжини, кратної 3, і правильним підходом буде додавання пробілу лише тоді, коли довжина кратна 3 І після нього має інше число. Це не виглядає проблемою, коли ваша локаль не визначає роздільник цифр як крапку ( .), це виглядає так:.999.999
ViniciusPires

PS .: Працювати з, $filter('number');здавалося б, кращим способом, він завантажує формат через $localeсервіс, і ви можете використовувати, new RegExp("\\"+$locale.NUMBER_FORMATS.GROUP_SEP, 'g');щоб змінити значення на модель ...
ViniciusPires

0

Angular має вбудовану функціональність формату дати , але щоб застосувати її до вхідних даних, де ви в кінцевому підсумку хочете отримати вихідну (неформатовану) дату, вам потрібно створити власну директиву .

Приклад директиви:

(function () {
    'use strict';

    angular.module('myApp').directive('utcDate', ['$filter', function ($filter) {
        return {
            restrict: 'A', //restricting to (A)ttributes
            require: 'ngModel',
            link: function (scope, elem, attrs, model) {
                if (!model) return;

                var format = 'MM/dd/yyyy h:mm:ss a';
                var timezone = 'UTC';

                //format the date for display
                model.$formatters.push(function (value) {
                    //using built-in date filter
                    return $filter('date')(value, format, timezone);
                });

                //remove formatting to get raw date value
                model.$parsers.push(function (value) {
                    var date = Date.parse(value);
                    return !isNaN(date) ? new Date(date) : undefined;
                });
            }
        };
    }]);
})();

Потім застосувати його:

<input type="text" ng-model="$ctrl.DateField" utc-date />

-3

Вам не потрібно буде створювати новий фільтр з нуля, оскільки angular вже має вбудований фільтр для типів дат. http://docs.angularjs.org/api/ng.filter:date

Я вважаю, що це саме те, що вам потрібно.


8
-1, OP запитував про конкретну проблему використання фільтра з ngModel, яка кардинально відрізняється від створення нового фільтра.
Валентин Васильєв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.