6

我有一個在我的DOM中多次執行的模板。AngularJS - 我的部分控制器

<div ng-controller="theController"> 
    content does not matter 
</div> 

因此,控制器被隔離很多次。 這是一個問題,因爲如果我在控制器

theController = function($scope) { 
    $scope.$on('myVar', function() { 
     // run one time for each time the template is repeated 
    }) 
} 

有關如何避免這種情況的任何想法把守望? 在此先感謝。

UPDATE

OK,我會盡量清晰。

也許我有一個表單,它是基於異步請求的響應動態構建的。

<form ng-controller="formController"> 
    <div ng-repeat="f in fields"> 
     <ng-inclide src="f.fields"></ng-include> 
    </div> 
</form> 

控制器是一樣的東西:

function formController($scope) { 
    $scope.fields = [{ template:'', ... }]; 
    // data come from an ajax request... 
    // here are static for the sake of simplicity. 
} 

所以我不知道哪些字段的形式被追加。

表單字段結構存儲在HTML的諧音......是這樣的:

<div ng-controller="inputController"> 
    <label> .... </label> 
    <input type="text" .... /> 
</div> 

<div ng-controller="selectController"> 
    <label> .... </label> 
    <select> 
     .... 
    </select> 
</div> 

function selectController($scope){ 
    $scope.$on("myCustomEvent", function(event) { 
     cionsole.info("Options were updated"); 
    }); 
} 

當表單具有比input type=textselect多,inputController,或者selectController被多次實例化。

爲什麼你不想每個實例都發生$ watch?

我想在發生特定事件時更新頁面中某個選項的選項。

我得到的是,而不是我更新頁面中的所有選擇。

從評論,我明白這是錯誤的,有更多元素與同一控制器在同一頁面。 因此,目前唯一可用的解決方案似乎是避免爲表單的每個元素定義控制器,對嗎?

UPDATE 2

$emitinputController使用:

function inputController() { 
    $scope.fireclick = function(p) { 
     if (p == 'specificInput') { 
      /* this is a temporary work around 
      I used to bind the event only with a specific field */ 

      $scope.$emit("myCustomEvent");  
     } 
    } 
} 

這是輸入場的的HTML所使用的部分的完整代碼:

<input type="text" ng-click="fireclick(f.name);" name="{{f.name}}" /> 

@任何人:

至少可以確認,(最終說爲什麼),有相同的頁面上使用相同的控制器更多的元素是錯誤

+0

控制器實例不能(也不應該)跨多個元素共享。你想要做什麼,爲什麼你不希望每個實例都出現'$ watch'?控制器本身就是你在DOM中使用它們的地方 - 它們不是在整個應用程序範圍內的 - 因此,如果多次觸發'$ watch'是一個問題,那麼你可能做錯了什麼。 – 2013-04-09 00:14:50

+0

是一個boradcast/emit的事件 – 2013-04-09 09:02:11

+0

@ArunPJohny我使用了$ rootScope。$ emit('myCustomEvent') – Bruno 2013-04-09 09:08:00

回答

4

這裏是我能夠做到的遞歸域的表單(基於在此SO回答:https://stackoverflow.com/a/15663410/1036025

結果[image link]:

enter image description here

視圖控制器它加載Home.html中局部用NG-視圖:

app.controller('HomeController', ['$scope', '$http', function ($scope, $http) { 
    $scope.msg = 'Home Page Message'; 
}]); 

形式控制器其內部Home.html中:

app.controller('NestedFormCtrl', ['$scope', function ($scope) { 
    $scope.formData = [ 
     {label:'First Name', type:'text', required:'true'}, 
     {label:'Last Name', type:'text', required:'true'}, 
     {label:'Coffee Preference', type:'dropdown', options: ["HiTest", "Dunkin", "Decaf"]}, 
     {label: 'Address', type:'group', Fields:[ 
      {label:'Street1', type:'text', required:'true'}, 
      {label:'City', type:'text', required:'true'}, 
      {label:'State', type:'dropdown', options: ["California", "New York", "Florida"]} 
     ]} 
    ]; 

    $scope.$watch('formData[3].Fields[1].label', function(newval, oldval) { 
     if (oldval !== newval) { 
      console.log('watch', oldval, newval); 
     } 
    }); 

    // this was added after and is not shown in the image 
    $scope.$watch('formData', function(newval, oldval) { 
     if (oldval !== newval) { 
      console.log('watch', oldval, newval); 
     } 
    }, true); 

    $scope.changefield = function() { 
     $scope.formData[3].Fields[1].label = 'Postal Code'; 
    } 

    $scope.customevent = function(field) { 
     var type = field.type; 
     // do something for this type 
     console.log('customevent', field); 
    }; 
}]); 

主頁局部視圖(這裏的模板ng-include中的路徑可能是您的字段的屬性,或者您可以使用開關盒並顯示您選擇的輸入/選擇:

<h1>{{msg}}</h1> 
<ul ng-controller="NestedFormCtrl"> 
    <li><button ng-click="changefield()">Change</button></li> 
    <li ng-repeat="field in formData" ng-include="'views/field.html'"></li> 
</ul> 

field.html模板(要麼每個類型字段的一個模板,或在field.type物業的開關情況下,一個主模板)

<button ng-click="customevent(field)">{{field.label}}</button> 
<ul> 
    <li ng-repeat="field in field.Fields" ng-include="'views/field.html'"></li> 
</ul> 
+0

你好,謝謝你的回答......你能分享一下views/field.html的代碼嗎? – Bruno 2013-04-11 21:08:57

+0

這是最後一塊代碼!它包含了遞歸本身,但是你首先將它包含在你的主視圖中。 – jpmorin 2013-04-11 22:51:46

1

下面是一個普拉克幫助你沿着這種情況下...

http://plnkr.co/edit/RvFrmPd4rlAM8aeFSwg7?p=preview

這只是如何可以做到這一點的說明。不知道你對錶單配置數據有多少控制,它不可能提供更全面的答案。在你想要知道的地方,如果你想要做一個$廣播($ emit在DOM播放器下降的時候注入$ rootScope,那麼更好)。因此$ rootScope的廣播將會到達整個應用程序。)

讓我知道,如果這可以幫助你。

+0

絕對完美我正在尋找,+1 – 2014-11-24 20:01:27

5

我認爲這樣做的角度是使用指令。我會在主視圖的ng-repeat中做一些像ng-switch一樣的事情,並且讓ng-switch只包含適當的指令......假設「輸入文本」指令的「輸入 - 下拉」指令存在:

<div ng-swtich on="field.type" ng-repeat="field in fields"> 
    <div ng-switch-when="text"><input-text ...></div> 
    <div ng-switch-when="dropdown"><input-dropdown ...></div> 
</div> 

相信這樣你不會有你現在有同樣的問題。我實際上沒有設置你想要做的事情,但我99%確定你應該使用指令!它們是您正在做的事情的理想選擇,並且可以重複使用。

我在http://angularlist.com上使用了一個指令來處理收視率,我可以很自信地說,當我在頁面上有多個電視時,他們不會穿過電線 - 也就是說,我沒有在那看任何東西,只是迴應事件...其實,讓我測試一下(測試.........)是的!我在我的評級指令正在編輯的模型值中添加了一塊手錶,當點擊評分時,只有一個觀察員被解僱 - 這是針對控制員的觀察員。這不是直播網站上,只是我的dev的服務器呆家裏,但這裏的指令,如果它可以幫助你:

app.directive("angularStars", function() { 
    return { 
    restrict: 'E', 
    scope: { 
     model: '=ngModel', 
     notifyId: '=notifyId' 
    }, 
    replace: true, 
    transclude: true, 
    template: '<div><ol class="angular-stars">' + '<li ng-class="{active:model>0,over:over>0}">1</li>' + '<li ng-class="{active:model>1,over:over>1}">2</li>' + '<li ng-class="{active:model>2,over:over>2}">3</li>' + '<li ng-class="{active:model>3,over:over>3}">4</li>' + '<li ng-class="{active:model>4,over:over>4}">5</li>' + '</ol></div>', 
    controller: function($scope, $attrs, $http) { 
     $scope.over = 0; 

     // TEST WATCH 
     $scope.$watch('model', function() { 
     console.log('modelChange', $scope.model); 
     }); 

     $scope.setRating = function(rating) { 
     $scope.model = rating; 
     $scope.$apply(); 
     if ($attrs.notifyUrl !== void 0 && $scope.notifyId) { 
      return $http.post($attrs.notifyUrl, { 
      id: $scope.notifyId, 
      rating: rating 
      }).error(function(data) { 
      if (typeof data === 'string') { 
       alert(data); 
      } 
      return $scope.model = 0; 
      }); 
     } 
     }; 
     return $scope.setOver = function(n) { 
     $scope.over = n; 
     return $scope.$apply(); 
     }; 
    }, 
    link: function(scope, iElem, iAttrs) { 
     if (iAttrs.notifyUrl !== void 0) { 
     return angular.forEach(iElem.children(), function(ol) { 
      return angular.forEach(ol.children, function(li) { 
      li.addEventListener('mouseover', function() { 
       return scope.setOver(parseInt(li.innerHTML)); 
      }); 
      li.addEventListener('mouseout', function() { 
       return scope.setOver(0); 
      }); 
      return li.addEventListener('click', function() { 
       return scope.setRating(parseInt(li.innerHTML)); 
      }); 
      }); 
     }); 
     } 
    } 
    }; 
}); 

指令是很難得到你的頭上纏 - 我仍然主要只是在拍攝與他們在一起的黑暗,試圖看出他們是如何工作的 - 但毫無疑問 - 你需要的力量在指令中。我強烈建議您閱讀AngularJS docs on writting directives,然後花時間看看其他人的指示 - GitHub上有很多可供學習的指導!

+1

我也會爲每個可重複使用的對象使用指令。 – maxdec 2013-04-15 09:12:01

+0

@Thom,你能解釋一下這段代碼中return語句的用法嗎?我從來沒有見過這樣的技術。 – graycrow 2014-04-04 14:30:33