Добавление ngModel для ввода с директивой

У меня есть элемент ввода, и я хотел бы привязать к нему ngModel и ngClass с помощью настраиваемой директивы, но у меня возникли проблемы.

Что у меня:

<input type="text" myDirective="PropertyFromScope" />

Что я хочу в результате:

<input type="text" ng-model="PropertyFromScope" ng-class="{'class' : MethodFromScope}" />

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

Вот что я получил до сих пор:

angular.module('customDirectives', [])
.directive('myDirective', function () {
    var linker = function (scope, element, attrs) {
        attrs.$set('ngModel', attrs.myDirective);
        attrs.$set('ngClass', '{\'class\' : MethodFromScope}');
    }
    return {
        restrict: 'A',        
        link: linker
    }
});

Здесь JSFiddle: http://jsfiddle.net/Q8QJJ/

Ответ 1

Вы пытаетесь это сделать?

Довольно простое решение:

myApp.directive('myDirective', function ($compile) {
    return {
        restrict: 'A',        
        compile: function(element, attrs) {
            element.attr('ng-model', attrs.myDirective);
            element.removeAttr("my-directive");
            element.attr('ng-class', '{\'class\' : testFunction()}');
            return {
               pre: function preLink(scope, iElement, iAttrs, controller) { },
               post: function postLink(scope, iElement, iAttrs, controller) { 
                 $compile(iElement)(scope);
               }
            }
        }
    }
});

Вот скрипка http://jsfiddle.net/V9e9M/

Ответ 2

Мне не удалось заставить это работать в функции компиляции (он добавил атрибуты, но, похоже, не заметил их). Однако эта функция привязки работает:

myApp.directive('myDirective', function ($compile) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var wrappedElement = angular.element(
                '<input type="' + attrs.type + '" ng-model="' 
                 + attrs.myDirective + '">');
            element.replaceWith(wrappedElement);
            $compile(wrappedElement)(scope);
        }
    }
});

Fiddle

Примечание. Я забыл добавить ng-класс, но я предполагаю, что ng-model работает, ng-класс должен работать.

Обновление

Здесь версия, использующая функцию компиляции:

myApp.directive('myDirective', function () {
    return {
        restrict: 'A',
        compile: function (tElement, tAttrs) {
            // for some unknown-to-me reason, the input must
            // be wrapped in a span or div:
            var tplElement = angular.element('<span><input></span>');
            var inputEl = tplElement.find('input');
            inputEl.attr('type', tAttrs.type);
            inputEl.attr('ng-model', tAttrs.myDirective);
            tElement.replaceWith(tplElement);
        }
    };
});

Fiddle

Ответ 3

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

Во-первых, в index.html я использую свою настраиваемую директиву с некоторыми атрибутами. Обратите внимание на штрих-код в html. Значения атрибутов - это то, что я хочу использовать в директиве.

index.html

<div>
    <form name="userInfo">
        <my-custom-directive for-model="ctrl.userInput"
                             for-label="Enter User Info"
                             for-other="more info for the directive">
        <my-custom-directive>
    </form>
</div>
// check to see the binding.
{{ ctrl.userInput }}

Далее, в partial.html, я собираюсь установить некоторые значения по умолчанию, чтобы увидеть, когда директива работает правильно, и когда я вижу значения по умолчанию.

partial.html

<div class="form-group">
    <label>blankLabel</label>
    <input type="text"
           class="form-control"
           ng-model="modelBlank">
</div>

Директива нуждается в другом синтаксисе, который, вероятно, является наиболее распространенной проблемой. Мне нравится определять переменную, поскольку я, вероятно, назначаю несколько атрибутов. Затем вызовите .attr() в переменной и передайте новую информацию, которую вы хотите применить. В этом случае буквально "ng-model" и значение настраиваемого атрибута, установленного в index.html.

directive.js

.directive('myCustomDirective', function () {
    return {
        templateUrl: 'partial.html',
        compile: function (element, attributes) {
            // Find the right element in the partial and assign a variable
            var inputTag = element.find('input');
            // use .attr() on the variable and pass it two arguments.
            inputTag.attr('ng-model', attributes.forModel);
            // Find a different element in the partial and replace the text.
            var labelTag = element.find('label');
            labelTag.html(attributes.forLabel);
        }
    };
})

Вы можете использовать console.log(element), но он будет генерировать много информации. Лучше осмотреть элемент после загрузки страницы, чтобы увидеть, что модель ng установлена ​​на пользовательское значение. Если он правильно подключен, {{ctrl.userInput}} на странице index.html должен отобразить текст, введенный в форму.

Это большая работа, но теперь myCustomDirective можно повторно использовать с другой переданной информацией:

<my-custom-directive for-model="ctrl.userName"
                     for-label="Enter Your Name:"
                     for-other="more info for the directive">
<my-custom-directive>
<my-custom-directive for-model="ctrl.userSelection"
                     for-label="Make a selection:"
                     for-other="more info for the directive">
<my-custom-directive>

Лично у меня никогда не было проблем с добавлением атрибутов или директив angular с помощью этого метода, включая такие вещи, как uib-typeahead. Не забудьте наблюдать различия в синтаксисе между html и javascript.