I need to dynamically add and initialize a set of controllers using AngularJS. I was able to add the controllers using the code below (based on 'UPDATE 2' of this answer) but don't understand how to pass data to the controls dynamically.
My code is below and also available as a JSFiddle. The goal is to have {{ field_name }}
and {{ field_type }}
populated in the templates once they are added -- right now they are blank. I tried to set these using ng-init
but that doesn't seem to work.
This is my first time using AngularJS and I'm coming from a Backbone background so I apologize I am missing something obvious and please feel to correct anything. Adding and initializing the controllers from a dynamic data structure defined on the client is a requirement of the project so I won't be able to render the page content on the server or make additional API calls. Thanks in advance.
Javascript:
DATA_FIELDS = [
{'field_name': 'name', 'field_type': 'str'},
{'field_name': 'location', 'field_type': 'str'},
{'field_name': 'is_active', 'field_type': 'bool'}
]
// Create base module and store providers for later use
providers = {};
editorApp = angular.module('editorApp', [],
function ($controllerProvider, $compileProvider, $provide) {
providers = {
$controllerProvider: $controllerProvider,
$compileProvider: $compileProvider,
$provide: $provide
};
}
);
// Boostrap base module
angular.bootstrap($('body'), ['editorApp']);
// Store our _invokeQueue length before loading our controllers
// This is just so we don't re-register anything
queueLen = angular.module('editorApp')._invokeQueue.length;
// Define controller for string field
angular.module('editorApp').controller('DisplayFieldStr',
function ($scope, $rootScope) {
}
);
// Define controller for boolean field
angular.module('editorApp').controller('DisplayFieldBool',
function ($scope, $rootScope) {
}
);
// Register the controls/directives/services we just loaded
var queue = angular.module('editorApp')._invokeQueue;
for(i=queueLen;i<queue.length;i++) {
var call = queue[i];
// call is in the form [providerName, providerFunc, providerArguments]
var provider = providers[call[0]];
if (provider) {
provider[call[1]].apply(provider, call[2]);
}
}
// Append templates to content div and set init attrs
for (i = 0; i < DATA_FIELDS.length; i += 1) {
field = DATA_FIELDS[i];
init_data = 'field_name=\''+field.field_name+'\', ';
init_data += 'field_type=\''+field.field_type+'\'';
div = $('.templates .df-' + field.field_type).clone().appendTo('.content');
div.attr('id', 'df-' + field.field_name);
controller_name = 'DisplayField' + field.field_type[0].toUpperCase() + field.field_type.substring(1);
div.attr('ng-controller', controller_name);
div.attr('ng-init', init_data);
}
// compile the new element
$('body').injector().invoke(function ($compile, $rootScope) {
for (i = 0; i < DATA_FIELDS.length; i += 1) {
field = DATA_FIELDS[i];
$compile($('#df-' + field.field_name))($rootScope);
}
$rootScope.$apply();
});
HTML:
<div class='content'></div>
<div class='templates' style='display: none;'>
<div class='df df-str'>
<ul>
<li>Template: df-str</li>
<li>Field name: {{ field_name }}</li>
<li>Field type: {{ field_type }}</li>
</ul>
</div>
<div class='df df-bool'>
<ul>
<li>Template: df-bool</li>
<li>Field name: {{ field_name }}</li>
<li>Field type: {{ field_type }}</li>
</ul>
</div>
</div>