2013-09-05 2 views
1

Я пытаюсь подключить адаптер, чтобы включить разметку, которую ASP.Net MVC испускает для проверки на стороне клиента для работы в AngularJS, и я столкнулся с интересной ошибкой. Если я динамически добавить атрибут required с помощью функции директивы компиляции:Динамическое добавление обязательного атрибута для выбора элемента

var myApp = angular.module('myApp', []).directive('valRequired', function() { 
    return { 
     compile: function (element) { 

      element.attr('required', 'required'); 

      return function() { /* other custom logic here */ } 
     } 
    }; 
}); 

select элемент не будет проверять по мере необходимости. Это только кажется проблемой при динамическом добавлении атрибута (jsFiddle).

Уточнение: Я хотел бы использовать MVC @Html.TextBoxFor(...) как есть. Для модели на основе DataAnnotations присваиваемые ею атрибуты data-val-* содержат информацию о том, какие проверки должны выполняться и какими должны быть сообщения об ошибках. Я не ищу помощь в подключении сообщений об ошибках, мне просто нужно подключить директиву, которая сообщает input, select и т. Д., Чтобы использовать проверку required.

+1

, как нг-требуется = "{выражение для испытания}"? – TheSharpieOne

+0

Не совсем. ASP.Net MVC испускает атрибут 'data-val-required', используя такие вещи, как' @ Html.TextBoxFor (...) 'и тому подобное.Я хотел бы автоматически преобразовать их в свои угловые эквиваленты и добавить некоторую проводку, чтобы отбросить переданные MVC сообщения проверки в приложение. – FMM

+0

Возможно, это поможет: http://stackoverflow.com/questions/4844001/html5-data-with-asp-net-mvc-textboxfor-html-attributes. Кроме того, 'ng-require' можно записать как' data-ng -require' и все равно будет разобран угловым. – TheSharpieOne

ответ

1

Позвольте мне начать с этого не очень, но он работает. Я пробовал разные способы заставить родительскую директиву работать, но безуспешно. Похоже, к тому времени, когда эта директива выполняется, слишком поздно.

Это будет искать атрибут, требуемый для ввода данных, и добавить подтверждение к элементу.

Это вызовет все те же вещи, так myForm.mySelect.$valid все равно будет работать, а также myForm.mySelect.$error.required

http://jsfiddle.net/TheSharpieOne/knc8p/

var myApp = angular.module('myApp', []).directive('valRequired', function() { 
    return { 
     require: 'ngModel', 
     restrict: 'A', 
     link: function (scope, elm, attr, ctrl) { 
      if (!ctrl || !attr.valRequired) return; 
      attr.required = true; // force truthy in case we are on non input element 

      var validator = function (value) { 
       if (attr.required && (value == '' || value === false)) { 
        ctrl.$setValidity('required', false); 
        return; 
       } else { 
        ctrl.$setValidity('required', true); 
        return value; 
       } 
      }; 

      ctrl.$formatters.push(validator); 
      ctrl.$parsers.unshift(validator); 

      attr.$observe('required', function() { 
       validator(ctrl.$viewValue); 
      }); 
     } 
    }; 
}); 


function MyCtrl($scope, $http) { 
    $scope.model = { 
     property: '' 
    }; 
} 
+0

Это, кажется, единственный способ заставить его работать, я согласен. Я сделал некоторый серфинг кода в кодовой базе AngularJS на GitHub. Похоже, что бит, который подключается к контроллеру 'ngModel', недоступен таким образом, который может быть использован вне директив' input' или 'select'. – FMM

0

UPDATE Я думал, лучшего способа, чтобы ответить на этот вопрос. Старый ответ ниже нового.


Вы можете получить ссылку на требуемую директиву AngularJS и применить ее самостоятельно. Heres пример кода, который будет делать это:

var myApp = angular.module('myApp', []).directive('valRequired', function(requiredDirective) { 
    var newDirective = {}, 
     angularDirective = requiredDirective[0]; //This assumes angular's required directive is the first one 

    //Copy over all other properties of the angular directive 
    angular.extend(newDirective, angularDirective); 

    //Change the name of our directive back to valRequired 
    newDirective.name = 'valRequired'; 

    //Provide our own logic in the linking function 
    newDirective.link = function(scope, element, attr, ctrl){ 
     //Super call 
     angularDirective.link.apply(this, arguments); 
     if(attr.valRequired === 'required'){ 
      attr.$set('ngRequired', 'true'); 
     } else { 
      attr.$set('ngRequired', 'false'); 
     } 
    } 

    return newDirective; 
}); 

<input data-val-required="required" ng-model="foo" /> 

OLD ОТВЕТ

Использование attr() метода JQuery в или jQLite не меняется AngularJs' Attributes object. Объект Attributes - это то, что директивы используют в качестве значений для своей логики.

Вам также потребуется указать атрибут ng-required, хотя вам не нужно связывать с ним какие-либо угловые выражения. Этот вопрос поможет вам там: Html5 data-* with asp.net mvc TextboxFor html attributes

Причиной этого является то, что нам нужно заставить угловым применить директиву к этому узлу. Обновление атрибута после этапа компиляции шаблона не будет уведомлять об угловом применении новых директив к узлу.

Это должно работать:

var myApp = angular.module('myApp', []).directive('valRequired', function() { 
    return { 
     priority : 101, //The priority needs to run higher than 100 to get around angularjs' default priority for ngRequired 
     link: function (scope, element, attr) { 

      if(attr.valRequired === 'true'){ 
       attr.$set('ngRequired', 'true'); 
      } else { 
       attr.$set('ngRequired', 'false'); 
      } 
     } 
    }; 
}); 

<input ng-required data-val-required="true" ng-model="foo" /> 
+0

Мне не удалось заставить это работать без добавления «тега ng-required» в тег, комментарии вопроса/вопроса, упомянутые выше, не были вариантом. – TheSharpieOne

+0

Требуется ng-требуется просто и будет включено или выключено в зависимости от значения данных-val-required. Это легко достижимо с помощью TextBoxFor. Обновленный ответ, чтобы уточнить этот вопрос –

+0

Что делает 'ng-repeat' что-то делать? – FMM

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