AngularJS and proper use of ngCloak - javascript

Quote from one of the comments regarding ngCloak directive (AngularJS documentation):
It is only really needed on your "index.html" page, because the
browser may try to render things before Angular has had a chance to
parse/compile it. At runtime, when Angular pulls in content due to
ng-view, ng-include, etc., it will be processed by Angular before the
browser renders.
I created a example in jsFiddle to verify this and on my surprise the expression is not evaluated before it is rendered in the browser. I would expect that the template will first be compiled & linked and then attached to the DOM - which is not the case.
Does that mean that every {{expression}} inside templates should also be wrapped in ngCloak to prevent flickering or am I missing something?

My guess is that the alert allow the browser to render before angular finished his job, adding a setTimeout with 0 delay show a rendered template:
http://jsfiddle.net/g/FLZZR/5/
function TemplateController ($scope) {
$scope.expression = "This should already be rendered...";
setTimeout(function(){
alert("... but it isn't.");
});
}
Additional note: you can't expect the template to be rendered at the point you place your alert, at best it would be hidden, angular use dirty checking to do its magic and you must let it "digest" your changes for them to show in the DOM.

Related

How to save and load a page with two angular2 components from local storage?

I have been trying to save and load a page with two angular2 components from local storage with the next code but the css from components is never applied.
This is my code to save:
localStorage.setItem('body', JSON.stringify(document.getElementById("body").innerHTML));
This is my code to load:
document.getElementById("body").innerHTML=JSON.parse(localStorage.getItem("body"));
I hope to have explained my problem well
Sorry, you cannot do that. Angular likes to take over a lot of the DOM, so you cannot just replace the entire body of the DOM. However, if instead of doing the entire "body", you did a subset, then you could do this:
<div [innerHTML]="htmlVar">
</div>
Where htmlVar is a variable you loaded with something like:
this.htmlVar = JSON.parse(localStorage.getItem("htmlVar"))
Watch out, by default innerHTML will strip out lots of "unsafe" html. You can reenable most of them by calling DomSanitizer. Please note that you cannot use any Angular features in the html, like links with routerLink.

Restart/reload Angular app

I'm working on a project with Yii2 and Angular. The structure of the code is as follows:
<html ng-app="myApp">
<head.../>
<body>
...
<div class="body-content"> MAIN CONTENT GOES HERE </div>
...
</body>
</html>
The page contains a header and a column on the left and a center area which is rendered inside the .body-content div. Now, as you can imagine, I have some buttons in there, some other angular widgets, etc..
Yii2 has a really cool feature called renderPartial that will re-render a view file without wrapping it again in the <head> and <body>. I use that to update the content of my main area, by calling that function, getting the response with jQuery and replacing the content.
Now, that causes all buttons that where binded with Angular to stop working (I'm guessing why). My question is: How can I make Angular re-run or re-bind all my (new) DOM elements to their actions?
You would have to use the manual bootstrap way (explained in https://docs.angularjs.org/guide/bootstrap) for angular but doing that would cause a memory leak over time as angular add listener on DOM that you destroy and is not aware of it's removal, so they stay, and so does for the controller / directives / binding and other features that are referenced by your code.
Is yii2 could be wrapped into an angular directive?
I am not sure if I am getting you right - you use a frontend framework AND a backend framework to control your frontend, the latter one deliveres new DOM content you inject into your HTML?
As far as I got it, Angular is best in handling everything while getting the data (be it from the backend in JSON or other format of your choice), NOT new DOM elements.
Angular itself binds to whatever DOM nodes it is added to, handles the content and dependency injection and thus displays your data. In your case the backend PHP framework seems to hand in new DOM elements that Angular thinks of "Hey - you don't want me to be adding them? fine, then I don't." and breaks.
Maybe there are solutions for this specific case, but if I were you I would rethink the concept in terms of "Where do I want my views/templates to be rendered? What part of the whole is responsible for what?" Using two different frameworks, let alone languages, to do the same job and interfering with one another would make a mess I wouldn't want to clean up.
So if you like this Yii2 feature and want to make it work, fine - but in that case - what do you need angular for? And if you'd rather stick to Angular you just have a backend that handles data and hands it back to the frontend to do it's job with it.

Angularjs, ng-view and custom document.ready logic

I am having a problem with angular js.
The thing is, I have bought a html template on the web which has custom javascript that is triggered on document.ready (contains a lot of code) and it does something with the GUI to set it all up and running.
As i switch my routes the the initial logic of the document.ready that was done for the elements inside the ng-view is lost and GUI looks awful.
Can someone tell me what is the best way to solve this issue?
When AngularJS changes the view/you switch your route, it will execute the associated controller-function. Therefore, you could call your initialization code from the controller.

Embed javascript in angular ui-router view

I'm really sorry if this has already been answered, but I have no idea how to search for it since it seems so specific.
I've got an AngularJS app using ui-router to dynamically load multiple views into the same <ui-view> element. I want to use Jquery UI's tooltip function on one of the h3 elements loaded dynamically by ui-router, but I don't know where to put the initializer such that it runs after the h3 is in the DOM.
Things I've tried:
Embedding a <script> tag in the HTML partial that calls $("h3").tooltip()
Putting the script tag in the main parent HTML template - with and without a document.ready wrapper
Putting the tooltip() function call in one of the angular js files that's loading the partial (when I changed the line to just alert(), it seemed that this code was running right before the partial is rendered, so there are no <h3>s yet)
I'm very confused as to how I can run arbitrary javascript code on dynamically loaded elements ... I think the first method should have worked. Even when I make the <script> tag just contain a simple alert(), nothing happens.
Any ideas? I'm also happy to provide more information, but I think I can't show the actual code due to an NDA.
may these will help you:
Embed javascript in angular ui-router view
AngularJS: How to make angular load script inside ng-include?
The approach you are taking to get that tooltip working is very wrong. Instead of trying to load a script dynamically inside a view, you should be wrapping the tooltip plugin inside a directive and assigning that directive to your h3 element. Or, even simpler, use Angular UI Bootstrap's Tooltip directive: http://angular-ui.github.io/bootstrap/
Mock code for custom directive:
'use strict';
angular.module('MyModule')
.directive('tooltip', function () {
return {
restrict: 'A',
link: function(scope, element, attrs) {
// initialize jQuery tooltip
// note element is a jqLite object with jQuery methods available
// DO NOT ATTEMPT TO WRAP element WITH jQuery
// ANGULAR CANNOT TRACK jQuery OBJECTS THAT
// ARE NOT WRAPPED WITH jqLite!!!
element.tooltip(...);
}
};
});

Building a Windows 8 Metro app with jQuery

I am just starting out with Windows 8 development using HTML/JS. I've spent the last few months immersed in jQuery development for apps targeting vehicle head-units and televisions.
Jumping into this, I thought the transition would be simple. I have the design and structure of my site all figured out for the most part and was hoping to follow some of the practices I had been using for my previous work.
That is, I want to essentially create a single page app. The main default.html file will house the top navigation/title and one other div. The other div will be used to load in all the other pages, all separate HTML files within the project.
All of the global functions and major functionality will reside in a javascript file, application.js. Then any page-specific javascript will reside at the top of each HTML file.
I'm quickly realizing that this is a problem. Using jQuery.load() to load in my pages causes security errors in my app.
JavaScript runtime error: Unable to add dynamic content. A script attempted to inject dynamic content, or elements previously modified dynamically, that might be unsafe. For example, using the innerHTML property to add script or malformed HTML will generate this exception. Use the toStaticHTML method to filter dynamic content, or explicitly create elements and attributes with a method such as createElement.
I was really hoping to avoid having to learn a bunch of Microsoft-specific stuff. I think it's great that they've provided a lot of tools and what not, and maybe I just haven't used them enough, but everything just feels too rigid for me and for what I'm trying to do or can already be accomplished with jQuery. I'm one who likes to know EXACTLY what is happening and have full control over it.
Also looking through the templates and sample projects, I really don't like all the repeated code. For instance, every single HTML file declaring all the same references. I want to write my references and sections like my title bar just once, and not have to copy/paste that code all over my project.
Is there a way to do things the way I was hoping, and create a single page app? Do they have their own substitute for jQuery's .load()?
Any help pointing me in the right direction would be much appreciated!
EDIT 8/14/2012:
I have tried using the fix from this question:
Using jQuery with Windows 8 Metro JavaScript App causes security error
This gets rid of the security warning and I can load in HTML using jQuery.load(). However, looking at DOM explorer, my HTML is being stripped of my scripts.
I have also tried wrapping my .load() call inside of MSApp.execUnsafeLocalFunction(), but yet again my file still gets stripped of all scripts. What gives?
I fixed by simply changing the line of jQuery that was causing the error.
jQuery-1.8.0, line 5566:
append: function () {
return this.domManip(arguments, true, function (elem) {
if (this.nodeType === 1 || this.nodeType === 11) {
self.appendChild(elem); // problem line
}
});
},
Changed to:
append: function () {
return this.domManip(arguments, true, function (elem) {
if (this.nodeType === 1 || this.nodeType === 11) {
var self = this;
MSApp.execUnsafeLocalFunction(function () {
self.appendChild(elem);
});
}
});
},
There is a "formal" way to do what you are seeking.
WinJS.Navigation is provided to support "single page apps". For example, the default.html would contain a markup that would represent where the dynamically loaded page content would go:
<div id="contenthost"
data-win-control="Application.PageControlNavigator"
data-win-options="{home: '/pages/home/home.html'}">
</div>
In the example above, the actual content page loaded is at /pages/home/home.html
In event handlers, you can simply do the following to load or navigate to another page:
WinJS.Navigation.nav("/pages/other/page.html");
True, it is not jQuery, but it works great :)
Depending on your app, if you are not intending to access any WinRT components, you can navigate your page to ms-appx-web which will change the security policy around the page, but you can't specify this from start up. You would have to do a navigate, and leverage that new securyt context.
The other option you have it to wrap the calls to JQuery with msWWA.execUnsafeLocalFunction function, which will enable all that unsafe code be pushed into the DOM

Categories