Why does finally and done of $animateCSS behave differently in UI Bootstrap Angular JS - angularjs

I am using UI Bootstrap for collapsing/expanding a div section based on user clicking a button similar to the example shown in the official site - UI Bootstrap-Collapse
I included the latest version of ui-bootstrap(0.14.2) but it was not showing the expected behavior. In particular the collapseDone() and expandDone() callbacks are never called after the $animateCSS is done the animations. (The animations are working properly, presumably because of the css transition property of the class 'collapsing' in twitter bootstrap.)
But when I inspected the UI Bootstrap site, I found that it's working properly as expected. (That's the class 'collapsing' is added during the animation and then removed after animation and then the class 'collapse' is added). So I checked the source code link for collapse collapse source code -github and found that finally is used for $animateCSS promise resolution rather than done in the ui.bootstrap.js code I included.
So could someone please explain the difference between finally and done methods of the $animateCSS function? The documentation [Angular Docs-$animateCSS][3] says that
there is also an additional method available on the runner called .done(callbackFn). The done method works the same as .finally(callbackFn), however, it does not trigger a digest to occur. Therefore, for performance reasons, it's always best to use runner.done(callback) instead of runner.then(), runner.catch() or runner.finally() unless you really need a digest to kick off afterwards.
So it looks like both should behave similarly. Could someone shed light on this, as there seems to be very little resources to learn about $animateCSS. (google search for $animateCss returns results for animate.css which seems to be part of the earler angular js verion (v1.2) - so that doesn't help)

I had forgotten to inject "ngAnimate" to my module. That way the animation by $animateCss was not successful, so the done() was never called. But finally will be called even if the animation is not successful.

Related

Non-angular page opened with click - angular not defined using ignoreSynchronization or waiting for Angular without

After a lot of research, and tinkering, I can't seem to actually get my Protractor test to do anything else other than have an Angular related error, even though I am using browser to avoid Angular being detected at all.
The test involves an Angular app, opening a dropdown in it, and clicking on the link for the console; the console opens a non-Angular admin page in a separate window.
So based on the many informative SO posts I found, I first used this...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
//expect for new window here
});
});
Which appeared to work, as I could get to the window through repl pretty easily.
The issue is when either of the following were added...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
One expect check the URL and the other checks for the header element on the page, which is a table header. When I run this, I get the following:
Error while waiting for Protractor to sync with the page: "angular could not be found on the window"
When I decide to use browser.ignoreSynchronization = true, both in the function, or in a beforeEach, with or without a following afterEach setting it to false, I get the following:
JavascriptError: angular is not defined
I can't seem to get any "useful" errors to help me debug it, and trying it in repl does not help, as I get the same issue.
To be comprehensive, trying my URL expect without getting the second window will give me the root, and the other will fail.
Just doing one or the other will cause the same problem.
Changing to regular syntax (element(by.css...)) does not change things.
So much for my first question...
It appears that my use of browser.getLocationAbsUrl() is meant to be used for an Angular page, and was causing my issue...
Essentially, even though I believed I was using pure Webdriver calls, that call still required Angular on the page to work...
As stated in another post, the use of browser.driver.getCurrentUrl() is a non-Angular call using Webdriver, and fixed the problem. Thus, the final code is the following...
browser.sleep(1000); //to wait for the page to load
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.driver.getCurrentUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
This works without setting ignoreSynchronization, BTW.
I realized it would probably be something relatively simple to fix it, just didn't expect I'd get it that quickly (I intended on submitting the question last night, but posted it this morning instead).
In any case, I hope this will at least be a good reference for anyone else facing the same issue.
Seems like getLocationAbsUrl is angular abs url.
Try using the native driver getCurrentUrl instead.
-- expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
++ expect(browser.driver.getCurrentUrl() ...

Material Design Lite rendering problems with Angular JS

I have some problems using Material Design Lite (getmdl.io). I followed the steps showed in the getmdl.io web in order to install it (actually I use bower), but I always have the same problem, when I change the ng-route in my web, some resources don't render properly, I need to reload the page to get it properly rendered, for example.
First I have this:
then when I reload, I get what I want:
What I cant understand is why other resources like google icons or buttons work correctly but the menu button on the nav bar and other resources like this one need to reaload the page in order to render properly.
I try to include the library using the hosted method and bower method.
Any idea what is going on?
i past in my code this function
angular.module('app', ['ngRoute']).
run(function($rootScope, xxxx, xxx){
$rootScope.$on('$viewContentLoaded', function(event, next) {
componentHandler.upgradeAllRegistered();
});
});
It worked perfect! Good luck..
Libraries like MDL work by waiting for the page to load using the DOMContentLoaded event, scanning the page for things like input elements and manipulating them with JavaScript so that they can inject the bits and pieces needed to work with their components. This works fine on static websites, but the DOMContentLoaded event only fires once, so when Angular performs a page transition, the DOM changes without MDL knowing about it.
Material Design Lite has a section in its FAQ about using MDL on dynamic websites:
Material Design Lite will automatically register and render all elements marked with MDL classes upon page load. However in the case where you are creating DOM elements dynamically you need to register new elements using the upgradeElement function. Here is how you can dynamically create the same raised button with ripples shown in the section above:
<div id="container"/>
<script>
var button = document.createElement('button');
var textNode = document.createTextNode('Click Me!');
button.appendChild(textNode);
button.className = 'mdl-button mdl-js-button mdl-js-ripple-effect';
componentHandler.upgradeElement(button);
document.getElementById('container').appendChild(button);
</script>
Of course, this probably isn't terribly easy to do in your case, since you'd have to manually find each new element and call upgradeElement on it.
Usually, instead of doing this sort of event-based DOM manipulation, Angular uses directives to initiate DOM changes. Consider using a library built to interoperate with Angular, instead, such as Angular Material.

angular event doesn't update page

I'm converting a page in a mvc application with a lot of inline jquery javascript to angular using typescript.
The first calls works fine but I have a problem: based on a selection in a dropdown, the event updates several controls in the view, make a few ajax calls and finally update the view with the data from the calls.
Seems the conversion is working fine, but at the end of the call the page isn't updated.
I tried to remove all the old jquery code to avoid problems.
batarang and java console reports no errors.
the final ajax call is done and the result shown in a debug.
All seems to work fine, but the page isn't updated.
How can I find the problem?
thanks
Without seeing any code, it's difficult to answer but if you bind an event to an element and want to update something in the callback, you will have to use $apply
scope.$apply(function () {
// your code
});
$apply will trigger a $digest cycle, and should be used when you want to update something while being outside angular's context.
Most likely you are not handling your asynchronous calls correctly. It's impossible to tell from your question but it is a very common mistake with symptoms as you describe.
Make sure you are updating your model within the .then() method of a promise returned from an $http request. For example
someFnDoingHttpRequest().then(function(data){
// updated the model with the data
})
Also (another common mistake) make sure someFnDoingHttpRequest() returns a promise.
If you want to "find the problem" then you can use the following option.
Go to Internet Explorer (10 or 11).
Select "Internet Options" from the settings menu.
Go to the "Advanced" tab (the last tab)
Settings are listed and select "Display a notification about every script error"
Deselect the "Disable Script debugging (Internet Explorer)" and "Disable script debugging (Other)"
Run the program again, you will get notification about the real issue that happens while displaying actual result.

tinyMCE aborts with "Object doesn't support this action".

I'm trying to use the AngularJS directive ui-tinymce with tinyMce 4.0.25 and IE10, and am unable to get it to work at all.
My html looks like this:
<textarea ui-tinymce ng-model="fubar"></textarea>
In my controller, I have:
$scope.fubar = "this is a <b>test</b>";
It all goes badly at these two lines in the tinymce initialization code itself.
Theme = ThemeManager.get(settings.theme);
self.theme = new Theme(self, ThemeManager.urls[settings.theme]);
The first line sets Theme to undefined and the last line aborts with the message "Object doesn't support this action". The value of ThemeManager.urls[settings.theme] is "http://localhost:57683/Scripts/tinymce/themes/modern", which seems right.
I can no longer find it, but I'd previously found a post where this issue was due to this code being executed before some other part of tinyMCE had been loaded. The solution there was to use a certain tinyMCE option that forced loading in a certain way, however that option has been removed in tinyMCE 4.x. Even more frustrating is that I had tinyMCE working for days with my own directive when suddenly this occurred. I've simplified this to just using ui-tinymce (with the same result) to rule out any of my code as the culprit.
Mea culpa! I'd switched to using tinymce.js instead of tinymce.min.js and didn't realize that the min code expects the theme to be modern/theme.min.js (which I had) but the unminified code expects the theme to be modern/theme.js.

AngularJS jquery.flot chart directive DOM collision

i'm working with angular js now for about ke 4 months and despite all the "first step failures" like not emphasising the async way anuglar thinks, I'm facing a problem I don't really understand. It's not that easy to describe.
I have a provider which registrates directives within the routeprovider's resolve function - during config phase. To compile programmatically preconfigured directives I create them on the specific controller call of each route. Acutally the directive I'm adressing here is a complex flotchart directive. It retrieves data from a rest api, transformes the retrieved data and prepares different kinds of option setups like proper stacked line charts or simple piecharts. Every single step takes its time, so I introduced promises to be sure that everthing is at it's right place before I finally call something like "$.plot".
So now I have the following situation: Imagine a singlepage app with two tabs. Each tab - like a first class menu item - refers to a new page with a new controller to process and new partials to render. For each page i have beside other directives one of these heavy flotchart directives to render. actually it takes about 5 seconds to render the chart. So we assume that we really start the app from beginning - like pressing F5. Now I enter the first page the first time and within the mentioned 5 seconds I switch tabs to enter the next page. I get to the next page, see different partials, layouts and stuff and a loading chart - but actually the directive of the first page is still bound to its link phase of that heavy flotchart directive (still preparing options for flot and calculating data to output graphically).
My problem is that this link phase actually really ends within a completely different template/route/controller context and gets stuck. It crashes with a console "replace" error from jquery.flot. I think this error means that flot tries to plot into a div which does not exist anymore. But that error occures just when I switch tabs during the link phase of the first page's heavy flot directive. It doesn't happen when the first page's chart is fully rendered and doesn't happen when the first page's directive hasn't entered its link phase (or am i missing something??). I tried placing some console.logs directly BEFORE hitting the jquery "$.plot" - remember only of the first page chart directive to dive into what's acutally happening. And the strange thing is when I manage to switch tabs within these magic 5 seconds, I still get the console log entries from the first page entry although I'm on a different page. And now guess what. That's strange - acutally two directive link phases are running side by side and one of them on a completely different view (or isn't it completely different, because its a singel page app?). Imagine I plot ("render") the chart in exactly the same div id - like $('#flot-chart'). so I have html parts containing id="flot-chart" on the first page AND on the second. when I now switch from the first to the second page (not finishing the first chart) I get the chart from the first page rendered in the #flot-chart div of the second page and like half a second later the actually correct chart rendered in that same div. So actually the link phase of the first page's chart directive ends in a completely different page in a way showing 2 charts consecutively. I know jquery.flot depends on DOM manipulation via jquery and that might be the problem (perhaps THAT'S the only real explanation for my problem), because jquery DOM manipulation is out from the angular way of life.
Or are there other explanations? I acutally solved the problem via $routeChangeStart listening and killing the $.plot process, but are there some hints, suggestions, explanations for that behaviour?
Plunker flot chart directive DOM collision
I have prepared a plunker which shows kind of a similar behaviour. i've delayed the creation of the directive and the directive's async data and option retrieval methods to somehow mock the behaviour of my app. this is non production code but describes simplified the way my problems occure. when you "fast click" the menu item one after the other many times, you can sometimes force angular to show 2 charts in one page. acutally one directive is linking and doing stuff in a different partial ? i know i'm missing something in my mind ... please give me a hint.
i used chrome for reproducing the error. stop the the plunker and press 'run'. directly after pressing 'run' click as fast as you can both links a couple of times.
Thanks a lot!

Resources