AngularJS and dynamic HTML - javascript

I've a HTML line with AngularJS directive that I am inserting dynamically through some jQuery controls that are being used since 2009. I cannot change this Control. However, I want to start using angular JS.
The generated HTML for a grid, column rating, is:
<div star-rating rating-value="1005" max="5"> </div>
What I want is to get this html compiled.
At present AngularJS is not able to see this dynamically generated HTML.
The only way I can think of is if I call a javascript function for each jQuery insert (The Grid control I am using can compile JavaScript function).
fnCompileDynamicHTML('<div star-rating rating-value=23 max=5></div>)
And function:
fnCompileDynamicHTML(html) {
return $compile(html)($scope) // or something?
}
I have followed what is mentioned here. However my application is complaining about:
App Already Bootstrapped with this Element.
Well it is not because it is a new object, and new inner HTML.
This is what I have in the loop of 100:
evt.row.cells[glbCandidateListColumnIndex.rank].innerHTML = '<div star-rating rating-value="' + rank + '" ></div>';
fnCompileDynamicAngularJS(evt.row.cells[glbCandidateListColumnIndex.rank]);
Please help.

You should either load Angular.js after the DOM compilation by your foreign library is done, calling angular.bootstrap (documented here), or you can force the compilation of that particular DOM node manually (harder!!!)
As an example:
angular.module('myApp', []).directive('myDirective', function () {});
angular.bootstrap(document.body, ['myApp']);
That should work already!

Related

Calling a function with ng directive from injected html via Google Chrome Extension

I'm trying to use a Chrome Extension as a complimentary tool for the web app I'm developing.
I used chrome.tab.executeScript to manipulate the DOM of the web app and append a button inside a DIV.
chrome.tabs.executeScript({
code: 'var e = document.createElement("div");' +
'e.innerHTML = "' +
'<button ng-click="myfnc()"></button>' +
'";' +
'document.getElementsByTagName("body").appendChild(e);'
});
The button is added/appended as expected.
<body>
<div>
<button ng-click="myfnc()"></button>
</div>
</body>
The button has ng-click attribute that points to function on the web app. The function is just a simple alert call.
myfnc():
alert('Hello!');
However, when I click on the button nothing happens. Do you have any idea why? Can injected html coming from Google Chrome Extension interact directly with the web page's code?
Creating an element with the attribute ng-click does not inform Angular that the element exists within the page, as parsing of the document occurs once during bootstrap. You therefore have an element which exists 'outside' of any Angular scope, meaning the attribute ng-click just exists and has not caused the corresponding directive (ngClick) to be invoked.
Providing of course that the page has Angular, you will want to use the $compile service along with the desired $scope to compile the element after it has been inserted into the page.
A comprehensive solution is outside of the scope of your question. (Why does nothing happen when the button is clicked?) If you want to read more about using injected code with Angular, read up on:
the angular.element#scope() method, which lets you pick up the $scope object of an element,
appending an angular.element using the append() method available on angular elements
using the derived $scope object in compiling elements such that Angular is aware of it
The steps you want to take are something like...
Get the $scope you want to insert the element within:
var angular = document.querySelector('body');
var scope = angular.element(angular).scope();
Insert the new element into the page:
var newElem = angular.element('div');
angular.append(newElem);
$compile the element with this $scope:
$compile(newElem)(scope);
More information on dynamically creating Angular elements can be found in the answer to this question.

Compile angular controller inserted by javascript dynamically?

Im working in an app that creates html dynamically. We started using angular so now we are trying to create html using angular.element() and defining a controller in it.
angular.element("<div ng-controller='myController'/>");
The problem is, that as it is created after the page renders (when an user clicks somewhere, for example), the html inserted is not working with angular, is like plain html. How can I solve it?
I use this way:
var template = angular.element(YOU_HTML_IN_STRING);
var linkFn = $compile(template);
var element = linkFn($scope);
angular.element(CSS_SELECTOR).html('').append(element);
If you don't have access to $compile. You can have a look here:
how can we use $compile outside a directive in Angularjs

angularjs directive: not replace nor transclude

I need to append a directive's template AFTER an input field. The original input field needs to remain - I can't just create a duplicate of it. My thought for this was to, in the controller, use jQuery to add a DIV after the input field, and add an attribute for the directive to the div. However, in practice, that doesn't work - the div is created and added, but the directive doesn't activate.
The problem, I know, is that the jQuery-added div is not yet recognized by the angularjs controller - it appears AFTER angularjs runs over the controlled html.
I know that part of the problem is that you're not supposed to use jQuery in the controller, but I honestly can't think of another way to do it. Is there some way to cause the angularjs controller to look at this new div?
The original HTML looks like the following.
<input name="generatedString_1234567890">
I run jquery over the page to add a controller to the body. The relevant code looks similar to this:
jQuery('body').attr('ng-controller','MainCtrl');
angular.module('app',['DataTools']);
angular.element(document).ready(function(){
angular.bootstrap(document, ['app']);
});
Inside the angularjs, I run a resource to get a json string containing the relevant changes to the DOM, in terms of attributes that need to get added to the inputs and certain understood flags that require specific coding. The relevant task I'm trying to accomplish looks like this, where $(this) is the input field for the DOM.
jQuery(document).find('input.FormField,select.FormField').each(function(){
// Inside a case statement based on certain flags
var d = $('<div/>');
d.attr("ng-model", 'adors.'+label);
// Relevant code that adds attributes to the div - including the required directives
$(this).hide().after(d);
}
I am trying to create code that looks more like this (VERY GENERIC):
<input name="generatedString_1234567890" ng-hide="true" ng-model="input.uniqueKey">
<div special-input="time" ng-model="input.uniqueKey">
<select ng-repeat="hour in hours">
<select ng-repeat="minute in minutes">
</div>

How to add angular js module inside an existing application

I am trying to add an angular JS module inside an already existing code. I'm actually trying to add a new piece of code inside it. The workflow goes like this. When a button is clicked, the JS takes a template and adds it to the dom. In this added template, i would like to insert the new angular JS module. I am trying to atleast show hello world inside the module but haven't been successful.
Let's say when a button is clicked, i'm adding the below tag to the dom
<div patient-details ng-controller='patientDetailsCtrl' id='patientDetails'></div>
This is added through jquery or javascript. How do i make it work with the below directive
angular.module('patientDetailsModule',[])
.directive('patientDetails',function($compile){
return{
//restrict: 'E',
template: "<div>Hello World!!!{{name}}</div>"
};
});
You need to use $compile. $compile() will make sure all the Angular code in your html snippet will be compiled!
Here is an example.
http://plnkr.co/edit/7Wr3oAtvZ8cn31uFFEOs?p=preview
Send Message from nc-click to directive
Directive receives message, compiles html and appends new element
var template = "<div patient-details ng-controller='patientDetailsCtrl' id='patientDetails'>Element added</div>";
var newElement = angular.element(template);
$compile(newElement)(scope);
element.append(newElement);
// can also use element.replaceWith(newElement);

Dynamically creating an angular view

I'm making an in game UI using awesomium, at some points the game loads up and executes a chunk of javascript which is meant to create arbitrary new UI elements. e.g.
jQuery(document.body).append('<span class="game-status-alert">You Lose!</span>');
That works nicely, the problem comes when I want to create some slightly more advanced UI elements, specifically using angular. For example something like:
function ChatBoxControl($scope) { /* Stuff */ }
jQuery(document.body).append(
'<div ng-controller="ChatBoxControl"><div ng-repeat="line in chat"><span>{{line}}</span></div></div>'
);
Not surprisingly, this does not create a new angular view. It simply adds that html to the document and never binds to the ChatBoxControl.
How can I achieve what I'm trying to do here?
You should $compile dynamically added angular content.
Something like:
jQuery(document.body).append(
$compile(
'<div ng-controller="ChatBoxControl"><div ng-repeat="line in chat"><span>{{line}}</span></div></div>'
)(scope)
);
scope for any element you can get using something like:
var scope = angular.element('#dynamicContent').scope();
Also you should get $compile that can be injected in other controller.
See also: AngularJS + JQuery : How to get dynamic content working in angularjs
You might want to use ng-include combined with ng-repeat.
Here is an simple example: http://plunker.no.de/edit/IxB3wO?live=preview
<div ng-repeat="dom in domList" ng-include="dom"></div>
Parent $scope will keep the list of partials loaded into the view.
And ng-repeat + ng-include will iterate over and display partials according
to the list.
When it is the right timing, you can append the partial into the dom list. e.g.
$scope.domList.push("chatbox.html");
(BTW, putting DOM manipulation into controller is not the angular way.)

Categories