Создание шаблонов данных в доступной для ng-модели

При использовании шаблонов на стороне сервера и на стороне клиента angularjs я не могу заставить angularjs распознавать значения, которые я использовал на сервере.

Например (или в jsfiddle):

<div ng-app>
<div ng-controller="Ctrl">
    <textarea ng-model="data" placeholder="Enter a name here">Templated in</textarea>
    {{data}}
</div>
</div>

Angularjs всегда будет заменять значение в текстовой области значением $scope.data (которое равно null). Я хочу, чтобы значение $scope.data выполнялось на "Templated in", в бутстрапе приложения, а затем продолжалось нормально оттуда.

Как я могу создать шаблон с сервера, а затем привязать его к клиенту с помощью модели angularjs?

Ответ 2

Я наткнулся на этот ответ, пытаясь понять это для себя, но мне никогда не нравилось, что мне нужно было перемещать информацию из той части поля, где это требует HTML-спецификация. Это просто не похоже на правильный подход ко мне.

Некоторое время я воспользовался тем, что Angular сидит поверх jQuery (или встроенного подмножества jqLite, если полный jQuery недоступен), чтобы решить эту проблему без перемещения содержимого или даже касания нг-INIT. В частности, вы можете получить доступ к содержимому текстового поля, используя (Angular/jqLite версия) стандартные методы jQuery во время фазы инициализации контроллера.

Итак, я просто сделал

var doc = angular.element(document.documentElement);

$scope.data = doc.find('textarea').eq(0).val();

в моем контроллере, где я хотел бы инициализировать любую другую переменную области видимости. (В качестве альтернативы здесь изменен jsFiddle...)

При наличии полной библиотеки jQuery код еще проще, поскольку у вас есть доступ к полному селекторам jQuery в этой точке и может прыгать прямо до $('textarea').eq(0).val() (или даже добавить id в поле и выбрать на нем: $('#data-textarea').val()).

Самое приятное в этом подходе заключается в том, что он будет работать для любых элементов формы, хотя большинство из них являются тегами <input>, а jqLite не поддерживает селекторов, поиск точного, который вы хотите, может быть довольно сложным. Я бы просто включил полную библиотеку jQuery в этот момент и воспользовался селекторами, но это меня.

Этот подход также имеет главный недостаток размещения DOM-кода в контроллере, который полностью нарушает соглашения Angular (Angular Way (TM)) и парадигму программирования MVC/MVVM. Не лучшее решение.

ОБНОВЛЕНИЕ: Итак, в конце концов я понял, что мне нужно более долгосрочное решение, которое не нарушало бы стольких передовых методов. Ответ на самом деле происходит из самого важного элемента Angular, без которого не будет работать ни одна из остальных (вы можете утверждать, что для других компонентов, но это просто более верно для этого): Директивы. Более конкретно:

app.directive('input', ['$parse', function ($parse) {
    return {
        restrict: 'E',
        require: '?ngModel',
        link: function (scope, element, attrs) {
            if(attrs.value) {
                $parse(attrs.ngModel).assign(attrs.value, scope);
            }
        }
    };
}]);

Это имеет ряд преимуществ. Во-первых, он не нарушает соглашения Angular, которые помогают усилить MVC/MVVM. Во-вторых, он даже не касается jqLite/jQuery, а также базовых функций DOM. В-третьих, он имеет желаемый эффект сохранения HTML-соглашений для определения значений по умолчанию, позволяя (или, по крайней мере, упрощая) использование Angular с другими существующими технологиями, такими как серверные механизмы шаблонов.

Почему это делает Angular по умолчанию? Ну, я не знаю фактического ответа без дополнительных исследований, но вероятный ответ заключается в том, что соглашения HTML поддерживают статическое содержимое страницы, а Angular - для динамического содержимого страницы. Это означает, что вы нарушаете HTML-соглашения во многих местах, не позволяя ему ограничивать возможности приложений Angular. Поскольку ожидается, что контроллеры несут ответственность за инициализацию моделей (и в большинстве случаев такое ожидание является правильным), команда Angular имела бы стимул игнорировать содержимое атрибута value (и его аналоги среди других теги формы).

Конечно, при таком подходе для любых применимых элементов, которые уже существуют до инициализации контроллера, инициализация контроллера может переопределить атрибут value. Однако это поведение непротиворечиво для всего приложения, поскольку новые элементы инициируют оценку директивы, но не фазу инициализации контроллера. (Частицы со своими собственными контроллерами также придерживаются этого поведения - элементы, находящиеся перед инициализацией частичного контроллера, могут быть переопределены упомянутым init, но другие элементы, добавленные после этого, не будут перезапускать init.)

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