Смотрите несколько переменных с полным именем неизвестно

57
7

У меня есть угловой контроллер:

function SignUpController($window, accountService) {

var vm = this;
vm.errors = null;
vm.user = null;

vm.submit = function (user) {

accountService.signup(user)

.then(function (response) {
$window.location.href = "/";
})

.catch(function (response) {
vm.errors = response.data.errors;
}

};

}

API возвращает список ошибок, если они существуют, следующим образом:

[
{code: "name", "message": "the name is required"}
]

Когда есть ошибки, я добавляю этот список в vm.errors. В HTML у меня есть:

<form name="form" ng-controller="SignUpController as vmsignup" ng-submit="vmsignup.submit(vmsignup.user)">
<input ng-model="vmsignup.user.email" name="vmsignup.user.email" type="text" />
<span class="error" validator="vmsignup.user.email"></span>
<!-- Other form fields -->
</form>

Директива просматривает vm.errors и заполняет все интервалы с помощью валидаторов с правильным сообщением об ошибке.

В моих контроллерах я всегда использую vm.errors, но в своем html я часто использую что-то еще, например vmsignup, поскольку у меня может быть несколько контроллеров.

Поэтому в этом примере директива должна иметь vmsignup.errors, чтобы она работала:

angular.module("app").directive("validator", validator);
validator.$inject = ["$parse"];

function validator($parse) {

var validator = {
link: link,
replace: false,
restrict: "A"
};

return validator;

function link(scope, element, attributes) {

scope.$watch("vmsignup.errors", function (errors) {

if (errors) {

var result = errors.filter(function (error) {

if (error.code == null)
return false;

var position = attributes.validator.lastIndexOf(".");

if (position > -1)
return attributes.validator.slice(position + 1).toLowerCase() === error.code.toLowerCase();
else
return attributes.validator.toLowerCase() === error.code.toLowerCase();

});

if (result.length > 0) {
element.show().text(result[0].message);
return;
}

}

element.hide();

});
}

Я бы хотел, чтобы директива имела что-то вроде:

scope.$watch("vm*.errors", ...

Полагаю, это невозможно, но должен быть способ решить это, нет?

Я думаю, что решение могло бы состоять в том, чтобы иметь новую директиву "валидацию", используемую в форме, чтобы сказать, что такое модель:

<form name="form" ng-controller="SignUpController as vmsignup" validation-model="vmsignup">

Тогда я буду использовать это в директиве validator:

scope.$watch(validator.model + ".errors", function (errors) {

Это хороший вариант? Это можно сделать? Кто-нибудь может мне помочь?

спросил(а) 2016-04-20T13:36:00+03:00 4 года, 5 месяцев назад
1
Решение
99

Вы не можете использовать * качестве подстановочного знака в выражении $watch, но вы можете посмотреть, например, коллекцию с $watchCollection...

Массив свойств:

$scope.$watchCollection('[prop1, prop2]', function(newValues, oldValues){
var newProp1 = newValues[0];
var newProp2 = newValues[1];
});

Массив функций, возвращающих значение:

$scope.$watchCollection([
function(){
return prop1;
}, function(){
return prop2;
}
], function(newValues, oldValues){
var newProp1 = newValues[0];
var newProp2 = newValues[1];
});

ОБНОВИТЬ

как сказал @Ambegodas, вы можете передать коллекцию errors качестве параметра в свою директиву. Таким образом, ваш код станет:

angular
.module("app")
.directive("validator", validator);

validator.$inject = ["$parse"];

function validator($parse) {

var validator = {
link: link,
replace: false,
restrict: "A"
};

return validator;

function link(scope, element, attributes) {

scope.$watch(attributes.errors, function (errors) {

if (errors) {

var result = errors.filter(function (error) {
if (error.code == null) return false;
var position = attributes.validator.lastIndexOf(".");
if (position > -1) {
return attributes.validator.slice(position + 1).toLowerCase() === error.code.toLowerCase();
}
return attributes.validator.toLowerCase() === error.code.toLowerCase();
});

if (result.length > 0) {
element.show().text(result[0].message);
return;
}
}

element.hide();

}, true); // << objectEquality == true

}
}

РАЗЛИЧНЫЙ ПРЕДЛАГАЕМЫЙ ПОДХОД

Вы можете создавать проверки на стороне сервера для тех входных данных, которые нельзя проверить только при проверке на стороне клиента.

HTML:

<form name="form" novalidate ng-submit="vm.submit(vm.account)">

<div class="form-group" mt-show-errors>
<label class="control-label" for="username">Username</label>
<input type="text" mt-validate-username class="form-control" name="username" id="username" ng-model="vm.account.username" required>
<div ng-show="form.$submitted || form.username.$touched">
<span ng-show="form.login.$error.required" class="help-block">Username is required</span>
<span ng-show="form.login.$error.mtValidateUsername" class="help-block">Username already taken</span>
</div>
</div>

<!-- more inputs -->

</form>

ДИРЕКТИВА:

  angular
.module('app.directives')
.directive('mtValidateUsername', mtValidateUsername);

function mtValidateUsername($timeout, MyAccountService) {
return {
require: 'ngModel',
scope: false,
link: function (scope, element, attrs, modelCtrl) {
var timeoutId;
modelCtrl.$parsers.push(function (inputValue) {
if (!inputValue) return '';
$timeout.cancel(timeoutId);
timeoutId = $timeout(function () {
MyAccountService.validateUsername(inputValue).then(function () {
modelCtrl.$setValidity('mtValidateUsername', true);
}).catch(function(){
modelCtrl.$setValidity('mtValidateUsername', false);
});
}, 1000); // 1 second throttle
return inputValue;
});
}
};
}

ответил(а) 2016-04-20T14:08:00+03:00 4 года, 5 месяцев назад
41

Пожалуйста, попробуйте подход ниже.


      var app = angular.module('MyApp',[]);

app.controller('MyCtrl',function($scope){
$scope.errors =1;
$scope.change = function(){
$scope.errors = 2;
}

});

app.directive('myDirecitive',function(){

return {
restrict:'A',
link:linkFunction
}

function linkFunction(scope,element,atrrs){

scope.$watch(atrrs.varName,function(newval,oldval){
console.log("watcher called");
});
}

});

<body ng-app="MyApp", ng-controller="MyCtrl">
<h1>Sample Application</h1>
<input type="text" my-direcitive var-name="errors"/>
<button ng-click="change()">Watch</button>
</body>

ответил(а) 2016-04-20T18:24:00+03:00 4 года, 5 месяцев назад
41

Вы можете использовать $ watchGroup для этой цели

ответил(а) 2016-04-20T13:48:00+03:00 4 года, 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема