簡體   English   中英

AngularJS - 我偏愛的控制器

[英]AngularJS - Controller of my partial

我有一個在我的DOM中多次使用的模板。

<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

好的,我會盡量讓自己更清楚。

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

<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 partials中......類似於:

<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=textselectinputControllerselectController被多次實例化。

為什么你不希望$ watch出現在每個實例中?

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

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

從評論中,我明白在同一頁面中擁有更多具有相同控制器的元素是錯誤的。 所以目前唯一可用的解決方案就是避免為表單的每個元素定義一個控制器,對吧?

更新2

$emit用在inputController中

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 partial中使用的輸入字段的完整代碼:

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

@Anybody:

至少可以確認,(並最終說明原因),在同一頁面上使用相同控制器的更多元素是錯誤的

我認為這樣做的Angular方法是使用指令。 我會在主視圖的ng-repeat中執行類似ng-switch的操作,並讓ng-switch只包含相應的指令...假設有一個“input-text”指令,則存在一個“input-dropdown”指令:

<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上使用一個指令來處理收視率,我可以自信地說,當我在頁面上有多個時,它們不會交叉連線 - 也就是說,我沒有在那里看任何東西,只是回應事件......實際上,讓我測試一下(測試.........)是的! 我在我的評級指令正在編輯的模型值中添加了一個監視,當點擊評級時,只有一個觀察者被觸發 - 一個用於控制器。 這不是在現場,只是我家里的開發服務器,但這是指令,如果它可以幫助你:

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文檔 ,然后花時間查看其他人的指令--GitHub上有很多可供學習的東西!

以下是我如何使用遞歸字段創建表單(基於此SO答案: https//stackoverflow.com/a/15663410/1036025

結果[ 圖片鏈接 ]:

在此輸入圖像描述

視圖控制器使用ng-view加載Home.html部分:

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屬性上有一個帶有switch case的主模板)

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

這是一個幫助您實現此方案的插件......

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

這只是說明如何實現這一目標。 如果不知道您對表單配置數據有多少控制權,那么就不可能提供更全面的答案。 如果你想知道,最好在你想要進行$ broadcast的地方注入$ rootScope($ emit會在$ tree播放時播出,而$ broadcast會播放下來..所以來自$ rootScope的$ broadcast將會到達整個應用。)

如果這有助於你,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM