AngularJS - Controller of my partial

angularjs, controller, javascript, model-view-controller, templates

Solution

Here is how I managed to do a form with recursive fields (based on this SO answer: https://stackoverflow.com/a/15663410/1036025)

Result [image link]:

The view controller which loads the Home.html partial with a ng-view:

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

The form controller which is inside 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);
    };
}]);

The Home partial view (here the template path in ng-include could be a property of your fields or you may use a switch case and display the input/select of your choice:

<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>

The field.html template (either have one template per type of field, or one main template with a switch case on the field.type property)

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

Problem

I've a template that is appendend many times in my DOM. ``` <div ng-controller="theController"> content does not matter </div> ``` So the controller is istantiated many times. This is a problem because if i put a watcher in the controller ``` theController = function($scope) { $scope.$on('myVar', function() { // run one time for each time the template is repeated }) } ``` Any ideas about how to avoid this? Thanks in advance. UPDATE OK, i will try to be clearer. Perhaps i've a form, that is built dynamically on the basis of the response of an asynchronous request. ``` <form ng-controller="formController"> <div ng-repeat="f in fields"> <ng-inclide src="f.fields"></ng-include> </div> </form> ``` The controller is something like: ``` function formController($scope) { $scope.fields = [{ template:'', ... }]; // data come from an ajax request... // here are static for the sake of simplicity. } ``` So I don't know what fields will be appended in the form. The form field structure is stored in html partials... something like: ``` <div ng-controller="inputController"> <label> .... </label> <input type="text" .... /> </div> ``` or ``` <div ng-controller="selectController"> <label> .... </label> <select> .... </select> </div> function selectController($scope){ $scope.$on("myCustomEvent", function(event) { cionsole.info("Options were updated"); }); } ``` When the form has more than an `input type=text`, or a `select`, the `inputController`, or the `selectController` are instantiated more than once. Why do you not want the $watch to occur for every instance? I would like to update the options of one of the selects in the page when a specific event occurs. What i get is instead that i update all the select in the page. From the comment, i understood that is wrong to have more element with the same controller in the same page. So currently the only available solution seem to me that is to avoid to define a controller for each element of the form, right? UPDATE 2 `$emit` is used in the 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"); } } } ``` This is the complete code of the input field used in the html partial: ``` <input type="text" ng-click="fireclick(f.name);" name="{{f.name}}" /> ``` @Anybody: Could at least confirm, (and eventually say why), to have on the same page more elements with the same controller is wrong

Original source

Related problems