2013-06-19 136 views
10

如果您需要更多信息或需要澄清任何內容,請讓我知道。我已經嘗試了很多不同的東西來解決這個問題,但還沒有找到解決方案。嵌套指令中的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> 

角指令:

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>' 
} 
}); 

角控制器:

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" 
      } 
     } 
    } 
}); 

回答

9

我好爲先前的代碼進行修改。試試這個: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>' 
    } 
+0

感謝您的快速響應!我嘗試了小提琴,但它似乎和我發佈的一樣。將其更改爲功能隔離範圍的目標是什麼? – princjef

+0

我添加了refobj,所以你不需要在指令中調用'firstname',因爲我確定你希望這是通用的。 – Nir

+0

這真的很聰明!沒有想過使用數組符號而不是點。這將符合我的需求。謝謝! – princjef

8

由於在指令中的文本框採用原語,而不是一個對象爲它的模型(ng-model="value"而非ng-model="someobj.somevalue" ),其模型僅在本地範圍內創建,並且父級無權訪問它。

解決方法是使用dot rule作爲對象屬性來定義指令文本框模型:

ng-model="value.firstname" 

然後通過整個user對象到該指令的,而不是僅僅在基本屬性:

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

Here is a demo

+0

哦,我看到我出錯了。感謝您的洞察力 – princjef

+0

嘿,我已經簡化了您的演示,只是爲了看清楚事情。它似乎適用於複雜的對象,但不適用於簡單的屬性... [這裏是更新版本](http://jsfiddle.net/BXRnM/4/)。你能明白爲什麼嗎? – Dmitry

+0

@Dmitry你的簡單屬性的例子重新引入OP的錯誤。簡而言之,Angular scope繼承_requires對象而不是簡單的基本變量_。這是JavaScript中原型繼承的直接後果。你可以看看[[這個答案](http://stackoverflow.com/questions/16928341/update-parent-scope-variable/16929117#16929117)]我給其他地方看到另一個例子或退房[[this問與答](http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs)]更詳細的解釋。 – sh0ber

0

問題我s由ng-switch引起,來自git的doc Understanding scope

ng-switch作用域繼承與ng-include類似。因此,如果您需要 雙向數據綁定到父範圍中的基元,請使用$ parent,或者將 更改爲對象,然後綁定到該對象的屬性。這將避免父範圍 屬性的子範圍隱藏/遮蔽。

所以如果您在文本框中鍵入一些文本。以下代碼的 將被執行爲ng-switch範圍。

$scope.value="the text you typed"

所以不會徵詢原型鏈搜索value。這將創建一個新的屬性ng-switch範圍。

如何作證?

如果將value更改爲$parent.value。一切都會正常工作。因爲在ng-switch爲原始類型(angularjs會認爲value爲原始類型,如果沒有點)$parent將參考formrow指令作用域。

嘗試刪除ng-switch或按照文檔所述操作。問題就會消失。

更重要的是,文檔建議我們在應用雙向綁定時總是使用點.來引用模型。

如果我說錯了什麼。請善待我,糾正錯誤。謝謝。