Tengo una cadena de filtrado de fecha en mi alcance.

$scope.myModel = {date:""};

También tengo un jQuery datepicker

<input date-value="myModel.date" date-picker />

Que actualiza esta cadena dentro de una directiva (usando AngularJS - Cambio de valor de entrada de directiva de atributo )

.directive('datePicker', function ($timeout) {
  return {
    scope: {
      dateValue: "=?",
    },
    link : function (scope, elem, attrs) {
      $timeout(function() {
        elem.data('date-value', scope.dateValue);
        elem.bind('change paste', function (blurEvent) {
          if (elem.data('date-value') != elem.val()) {
            console.log('value changed, old value is:' + elem.data('date-value') +'new value is: ' + elem.val());
            elem.data('date-value', elem.val());
            scope.dateValue = elem.val();
          }
        });
      });
    },

  };
});

La fecha del alcance raíz se está actualizando correctamente y puedo enviarla con éxito a un servidor, pero quiero hacer algo cuando cambie la fecha. Mi función se llama una vez en la inicialización de la página y luego nunca más.

$scope.$watch("myModel.date", function(newVal, oldVal) {
  console.log("newVal: " + newVal + '  oldVal:' + oldVal);
  if (newVal == oldVal) {
    return;
  }
  // do something 
});

¿Qué estoy haciendo mal aquí?

1
James 6 feb. 2015 a las 03:34

2 respuestas

La mejor respuesta

Leí en alguna otra publicación de desbordamiento de pila que podría forzar las verificaciones en su alcance a través de scope.apply () pero el alcance en mi resumen no era el mismo alcance que en mi controlador. Entonces esto funciona, pero no sé lo suficiente sobre ángulos y resúmenes para explicar por qué.

elem.bind('change paste', function (blurEvent) {
          if (elem.data('date-value') != elem.val()) {
            console.log('value changed, old value is:' + elem.data('date-value') +'new value is: ' + elem.val());
            elem.data('date-value', elem.val());
            scope.dateValue = elem.val();
            if (!scope.$$phase) {scope.$apply();}
          }
        });

De todos modos, esto parecía demasiado complicado y el enlace del elemento se activaba cuando hice clic en el cuadro antes de terminar de seleccionar. Terminé configurando una llamada de función en onClose en los parámetros jQuery datePicker.

datePickerParams = {
    controlType     : "select",
    timeFormat      : "hh:mm TT",
    onClose         : function(dateText, inst) {
                          $scope.myModel.dateText = dateText;
                          // do stuff
                      }
};

Y luego simplemente pasarlo a la directiva.

.directive('datePicker', function ($timeout) {
  return {
    scope: {
      datetimePickerParams: "=",
    },
    link : function (scope, elem, attrs) {
      $timeout(function() {
        elem.datetimepicker(scope.datetimePickerParams)
      });
    },
  };
});

(tal vez es hora de revisar los recolectores de fechas angulares y alejarse de los jquery).

1
James 7 feb. 2015 a las 00:24

¿Has intentado llamar a $ watch con true como tercer argumento?

$scope.$watch("myModel.date", function(newVal, oldVal) {
  console.log("newVal: " + newVal + '  oldVal:' + oldVal);
  if (newVal == oldVal) {
    return;
  }
  // do something 
}, true);

Esto verificará la igualdad de valor en lugar de la igualdad de referencia.

Consulte la documentación de $ watch aquí para comprender la función del tercer parámetro [objectEquality]. Básicamente, estableciéndolo en verdaderas causas => "Comparar la igualdad del objeto usando angular.equals en lugar de comparar la igualdad de referencia".

Además, probablemente sería mejor mirar una bandera booleana en lugar del objeto. Cambie la bandera booleana al cambiar su `myModel.date 'y observe esa bandera en su lugar. Eso reduciría la sobrecarga de rendimiento: verificar el objeto es costoso que verificar una bandera booleana.

¡Espero que esto ayude!

0
amitthk 6 feb. 2015 a las 05:30