Verwenden des Winkelfilters im Eingabeelement

74

Ich hoffe, ich habe nichts Offensichtliches im Dokument verpasst, wenn ich es habe, bin ich sicher, dass jemand helfen wird.

Ich verwende asp.net webapi, um ein DTO mit Datumsfeldern zurückzugeben. Diese werden mit JSON.Net (im Format '2013-03-11T12: 37: 38.693') serialisiert.

Ich möchte einen Filter verwenden, aber ist dies in einem INPUT-Element möglich oder sollte ich einen neuen Filter oder eine neue Direktive erstellen, um dies zu erreichen?

// 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'}}

Gibt es eine Verknüpfung, die mir fehlt?

Leon
quelle

Antworten:

131

Kurz gesagt: Wenn Ihre Daten in der Ansicht und im Modell eine andere Darstellung haben sollen, benötigen Sie eine Direktive , die Sie sich als Zwei-Wege-Filter vorstellen können .

Ihre Richtlinie würde ungefähr so ​​aussehen

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" /> 

Hier ist ein funktionierendes jsFiddle- Beispiel.

holographisches Prinzip
quelle
5
Sieht gut aus, aber wie würden Sie es anwenden? Wie kann man einen Filter angeben, der bei der Formatierung verwendet werden soll?
Paul Taylor
@PaulTaylor beschränkt diese Anweisung nur auf 'Attribut' und verwendet dieses Attribut in einem Eingabefeld (ähnlich wie Sie schreiben <input ng-model="foo">.
Aditya MP
Schauen Sie sich auch diese Antwort an, um ein ausführlicheres Beispiel zu erhalten.
Aditya MP
Arbeitsbeispiel zu JSFiddle?
ViniciusPires
Vielen Dank! Das einzige, was Ihrem Beispiel für meine Lösung fehlte, war, das Modell auf Änderungen zu überwachen und den Formatierer erneut auszuführen. Ich habe nicht verstanden, wie ich das mit AngularJS so einfach erreichen kann, ich musste das Element-Update erzwingen:scope.$watch(attrs.ngModel, function(value){ element.val( $filter('number')(value, 0) ); });
ViniciusPires
20

Unterschiedliche Werte in Ihrem Eingabefeld und in Ihrem Modell zu haben, widerspricht der Natur des ng-Modells. Ich schlage daher vor, dass Sie den einfachsten Ansatz wählen und Ihren Filter innerhalb des Controllers anwenden, eine separate Variable für das formatierte Datum verwenden und Beobachter einsetzen, um formatierte und ursprüngliche Daten synchron zu halten:

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'};

});
Stewie
quelle
6
Ich glaube, dass die Schaffung einer neuen Richtlinie zur Erfüllung der Anforderungen hier eine sauberere Lösung ist. Wenn ich das Problem des OP richtig verstanden habe.
Holographisches Prinzip
Du hast recht. Es ist sauberer. Ich wollte @leon nur eine Option geben, falls er / sie mit benutzerdefinierten Anweisungen noch nicht so vertraut ist.
Stewie
Vielen Dank, beide Antworten sind dankbar, da es großartig ist, alternative Methoden zu lernen.
Leon
3
-1, zwei Variablen + Beobachten ist eine Hölle der Unterstützung. Stellen Sie sich einen Bereich mit Dutzenden von Variablen vor (Versicherungsrechner usw.)
Valentin Vasilyev
16

Wenn Ihre Eingabe nur Daten anzeigt

Wenn Sie tatsächlich eine Eingabe benötigen, um einfach einige Informationen anzuzeigen, und es sich um ein anderes Element handelt, das das Winkelmodell ändert , können Sie eine einfachere Änderung vornehmen.

Anstatt eine neue Direktive zu schreiben, BENUTZEN Sie einfach NICHT die ng-modelund verwenden Sie gut, alt value.

Also statt:

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

Das wird es tun:

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

Und funktioniert wie ein Zauber :)

Atais
quelle
3

Vollständiges Beispiel, das Zahlen formatiert und alle 3 Zeichen Leerzeichen einfügt, beginnend am Ende:

'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, '')

Verwendung:

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

Plunkr-Beispiel: http://plnkr.co/edit/qo0h9z

Valentin Vasilyev
quelle
Was genau macht modelCtrl. $ Parsers (oder Formatierer) .push?
Vincent
1
@Vincent fügt dem Array von Formatierern eine Funktion hinzu, die aufgerufen wird, wenn der Wert aus dem Modell angezeigt werden muss. Stellen Sie sich das $ formatters-Array als eine Pipeline vor, die mit Funktionen gefüllt ist, bei denen jede Funktion aufgerufen wird und das Ergebnis weiter durch die Pipeline geleitet wird. Sobald alle Funktionen aufgerufen wurden, wird das Endergebnis angezeigt. Die $ parsers sind eine ähnliche Sache, aber für das Schreiben zum Modell.
Valentin Vasilyev
Ich glaube nicht, dass das tatsächlich funktioniert. Hast du einen Plunker oder ähnliches?
Mattcole
1
Nett! Das einzige Problem besteht darin, dass ein Leerzeichen vor der Zahl in einem beliebigen Längenmultiplikator von 3 hinzugefügt wird. Der richtige Ansatz besteht darin, das Leerzeichen nur dann hinzuzufügen, wenn die Länge ein Vielfaches von 3 ist UND eine andere Zahl dahinter steht. Es sieht nicht nach einem Problem aus, wenn Ihr Gebietsschema das Zahlentrennzeichen nicht als Punkt ( .) definiert. Es sieht folgendermaßen aus:.999.999
ViniciusPires
PS.: Die Arbeit mit $filter('number');schien eine bessere Möglichkeit zu sein, es lädt das Format über den $localeDienst und Sie können new RegExp("\\"+$locale.NUMBER_FORMATS.GROUP_SEP, 'g');den Wert auf das Modell umkehren ...
ViniciusPires
0

Angular verfügt über eine integrierte Datumsformatfunktion. Um diese jedoch auf eine Eingabe anzuwenden, bei der Sie möglicherweise das unformatierte (unformatierte) Datum erhalten möchten, müssen Sie eine benutzerdefinierte Direktive erstellen .

Beispielrichtlinie:

(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;
                });
            }
        };
    }]);
})();

Dann, um es anzuwenden:

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

Sie müssten keinen neuen Filter von Null erstellen, da Angular bereits einen Filter für Datumstypen integriert hat. http://docs.angularjs.org/api/ng.filter:date

Ich glaube, genau das brauchen Sie.

odiseo
quelle
8
-1, OP fragte nach dem spezifischen Problem der Verwendung eines Filters mit ngModel, das sich drastisch von der Erstellung eines neuen Filters unterscheidet.
Valentin Vasilyev