Угловое связывание данных с помощью AngularJS в вложенных директивах

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

Я относительно новичок в angularJS, и я пытаюсь создать приложение с несколькими слоями данных. У меня есть основная информация пользователя, хранящаяся в области тела на контроллере PageController. Затем у меня есть форма настроек, которая загружается с использованием $routeParams (с контроллером SettingsController), который включает в себя несколько пользовательских директив для целей шаблонов. Поскольку директивы являются вложенными, я использую transclusion для загрузки второго внутри первого. Кажется, все работает нормально.

Моя проблема в том, что я пытаюсь ссылаться на поле user.firstname изнутри самой внутренней директивы и хочу использовать двустороннюю привязку данных, чтобы изменения, внесенные в текстовое поле, также приводили к изменению значения в области PageController. Я знаю, что многие из этих проблем вызваны использованием примитивов в ng-модели, но я попытался поместить все в дополнительный объект, чтобы я запускал прототипное наследование безрезультатно. Что я здесь делаю неправильно?

Здесь JSFiddle моего кода, урезанный как можно больше, чтобы изолировать проблему. В этом примере, если я ввешу внешнее текстовое поле, которое находится непосредственно в области PageController, оно изменит внутреннее текстовое поле до тех пор, пока это текстовое поле не будет изменено, при котором соединение будет нарушено. Это похоже на проблему использования примитивов, как описано в других вопросах, но я не могу понять, где проблема здесь.

HTML:

<body class="event-listing" ng-app="app" ng-controller="PageController">
    <div class="listing-event-wrap">
        <input type="text" ng-model="user.firstname" />
        <div ng-controller="SettingsController">
            <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}">
                <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" value="user.firstname"></div>
            </section>
        </div>
    </div>
</body>

Angular Директивы:

app.directive('formrow', function() {
return {
    scope: {
            label: "@label",
            type: "@type",
            value: "=value" 
    },
    replace: true,
    template: '<div class="form-row">' + 
            '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
            '<div class="form-entry" ng-switch on="type">' + 
                '<input type="text" ng-model="value" data-ng-switch-when="textInput" />' + 
            '</div>' + 
        '</div>'
}
});
app.directive('block', function() {
return {
    scope: {
            title: "@title",
            description: "@description" 
    },
    transclude: true,
    replace: true,
    template: '<div class="page-block">' +
            '<h2 data-ng-show="title">{{title}}</h2>' + 
            '<p class="form-description" data-ng-show="description">{{description}}</p>' + 
            '<div class="block-inside" data-ng-transclude></div>' + 
            '</div>'
}
});

Angular Контроллеры:

app.controller("PageController", function($scope) {
    $scope.user = {
        firstname: "John"
    };
});
app.controller("SettingsController", function($scope) {
    $scope.data = {
        updateInfo: {
            title: "Update Your Information",
            description: "A description here",
            labels: {
                firstname: "First Name"
            }
        }
    }
});

Ответ 1

Прошу прощения за предыдущий код. Вместо этого попробуйте: http://jsfiddle.net/CxNc2/2/

Вместо передачи фактического значения я теперь передаю объект + указатель на правильное значение внутри. Я добавил 'refobject' здесь:

<body class="event-listing" ng-app="app" ng-controller="PageController">
    <div class="listing-event-wrap">
        <input type="text" ng-model="user.firstname" />
        <div ng-controller="SettingsController">
            <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}">
                <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" refobj='user' value="firstname"></div>
            </section>
        </div>
    </div>
</body>

и я добавил значение refobj + здесь:

app.directive('formrow', function() {
    return {
        scope: {
            label: "@label",
            type: "@type",
            value: "@value",
            refobj: "="
        },
        replace: true,
        template: '<div class="form-row">' + 
            '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
            '<div class="form-entry" ng-switch on="type">' + 
        '<input type="text" ng-model="refobj[value]" data-ng-switch-when="textInput" />' + 
            '</div>' + 
        '</div>'
    }

Ответ 2

Поскольку текстовое поле в директиве использует примитив вместо объекта для своей модели (ng-model="value", а не ng-model="someobj.somevalue"), его модель создается только в локальной области, а родитель не имеет к ней доступа.

Исправление состоит в том, чтобы определить модель текстового поля директивы, используя правило dot в качестве свойства объекта:

ng-model="value.firstname"

Затем передайте весь объект user в директиве вместо свойства примитива:

<div formrow ... value="user"></div>

Вот демонстрация

Ответ 3

Проблема вызвана ng-switch, из документа Понимание области от git.

Наследование ng-switch работает так же, как ng-include. Так что если вам нужно 2-сторонняя привязка данных к примитиву в родительской области, используйте $parent или изменить модель как объект и затем привязать ее к свойству объект. Это позволит избежать скрытия/скрытия детской области родительской области свойства.

поэтому, если вы введете текст в текстовое поле. ниже код будет выполнен для области ng-switch.

$scope.value="the text you typed"

Поэтому он не будет обращаться к цепочке прототипов для поиска value. Это создаст новое свойство для области ng-switch.

Как это подтвердить?

Если вы измените value на $parent.value. все будет хорошо работать. потому что в ng-switch для примитивного типа (angularjs распознает value как примитивный тип, если нет точки) $parent будет ссылаться на область действия formrow.

Попробуйте удалить ng-switch или сделать, как говорит документ. проблема исчезнет.

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

Если я сказал что-то не так. Пожалуйста, любезно поправьте меня и сделайте это правильно. Спасибо.