tag:blogger.com,1999:blog-60157454926067516862024-02-19T11:22:07.987+01:00Kvetis.com: Programming a new universe!About web development and other funny stuff.Martin Večeřahttp://www.blogger.com/profile/15451621886034236096noreply@blogger.comBlogger3125tag:blogger.com,1999:blog-6015745492606751686.post-12544542168175681542014-10-18T19:20:00.001+02:002014-10-18T19:20:18.270+02:00Angular Request Count & Loading Widget (ng 1.3.0)<p>I my older post (<a href="http://www.kvetis.com/2014/01/angularjs-loading-widget.html" target="_blank">AngularJS Loading Widget</a>) I have described how to count requests and keep track of their count to be able to notify user when something gets loaded. In the new version 1.3.0 of Angular the response transformer is not called when the request fails or returns empty response. I have updated to Interceptors. I’ve avoided using them for this purpose because I was not getting constant results with them. But now I don’t know of other options. Here’s the updated code of the <font face="Consolas">.config</font> phase. Please let me know if you come across any issues. <a href="http://jsfiddle.net/kvetis/zzcL05zr/2/" target="_blank">Working JSFiddle demo</a>. If you want to know how this works, read the older <a href="http://www.kvetis.com/2014/01/angularjs-loading-widget.html" target="_blank">post</a>.</p><pre class="csharpcode">angular.module(<span class="str">'myApp'</span>, [<br /> <span class="str">'myApp.services'</span>,<br /> <span class="str">'myApp.directives'</span>,<br /> <span class="str">'myApp.controllers'</span>])<br /> .config(<span class="kwrd">function</span> (<br />$httpProvider,<br />requestNotificationProvider) {<br /> $httpProvider.interceptors.push(<span class="kwrd">function</span> ($q) {<br /> <span class="kwrd">return</span> {<br /> request: <span class="kwrd">function</span> (config) {<br /> requestNotificationProvider.fireRequestStarted();<br /> <span class="kwrd">return</span> config;<br /> },<br /> response: <span class="kwrd">function</span> (response) {<br /> requestNotificationProvider.fireRequestEnded();<br /> <span class="kwrd">return</span> response;<br /> },<br /> <br /> responseError: <span class="kwrd">function</span> (rejection)<br /> {<br /> requestNotificationProvider.fireRequestEnded();<br /> <span class="kwrd">return</span> $q.reject(rejection);<br /> }<br /> }<br /> });<br />});</pre> Martin Večeřahttp://www.blogger.com/profile/15451621886034236096noreply@blogger.com0tag:blogger.com,1999:blog-6015745492606751686.post-8769876356958409612014-01-17T15:55:00.001+01:002014-01-17T15:56:25.734+01:00AngularJS and Bootstrap form-group (control-group) error highlighting–globally<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZs2qF9I1Ypr8t3mRBkITpc0JBa9Uq1IIWGuaIOodYLF1Q-Zh-B829yXeCu-yjmq0exG5WAjkfpR7h-wPDW6fA7jitwT6qHK3XmP608rgDp9FEG4xx8bd86XhJN8uKFV1d2NgPYeMx9Dwd/s1600-h/bootstrap_error%25255B6%25255D.png"><img title="bootstrap_error" style="float: left; margin: 0px 15px 0px 0px; display: inline" alt="bootstrap_error" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihkX5E3nj3IKkffgvkaPns-h0bbBLT48epJT3VEZBBlfSWbSCsgc3WDG0zspaYkIC-0ea66xyGvpf-pBXWIRARp2hOjQBBRKDTPNV5dMS3IP1sgy5V6_tGs-fxWN979k61CgL73t7iJ8xK/?imgmax=800" width="148" align="left" height="67"></a>If you use angularJS with Bootstrap, you would probably like to use bootstrap error highlighting using form-group (ex control-group). You could use <font face="Consolas">ng-class</font> directive with an expression to add the class on every <font face="Consolas">form-group</font> you use in your application. Or you could create a directive to add this feature on one place. In this post, I’ll explain how to do it.</p> <p>Let’s start with an simple example. (<a href="http://jsfiddle.net/kvetis/Pemat/6/" target="_blank">Most advanced</a> is at the end of the article.) In <a href="http://jsfiddle.net/kvetis/Pemat/4/" target="_blank">this simple JSFiddle</a> you can see two directives which add the functionality. First is the <font face="Consolas">form-group</font> directive:</p><pre class="csharpcode">app.directive(<span class="str">"formGroup"</span>, <span class="kwrd">function</span> () {<br /> <span class="kwrd">return</span> {<br /> restrict: <span class="str">"C"</span>,<br /> link: <span class="kwrd">function</span> ($scope, element, attributes) {<br /> <span class="kwrd">var</span> errorList = {};<br /> $scope.$on(<span class="str">"inputError"</span>, <span class="kwrd">function</span> () {<br /> element.addClass(<span class="str">"has-error"</span>);<br /> });<br /> $scope.$on(<span class="str">"inputValid"</span>, <span class="kwrd">function</span> () {<br /> element.removeClass(<span class="str">"has-error"</span>);<br /> });<br /> },<br /> <span class="rem">//own scope, so emitted messages don't get mixed up</span><br /> scope: <span class="kwrd">true</span><br /> };<br /></pre><br /><p>It simply listens in its own scope to two events: “<font face="Consolas">inputError</font>” on which it adds <font face="Consolas">has-error</font> class to the <font face="Consolas">formGroup</font> and <font face="Consolas">inputValid </font>on which it removes the same class. So whenever you add a form group, the directive listens on the scope to messages.</p><br /><p>Here is how and when I send them. I use another directive for that.<pre class="csharpcode">app.directive(<span class="str">"input"</span>, <span class="kwrd">function</span> () {<br /> <span class="kwrd">return</span> {<br /> restrict: <span class="str">"E"</span>,<br /> <span class="rem">//require the access to the controller of ngModel</span><br /> <span class="rem">//its injected as the 4th parameter of link function</span><br /> require: <span class="str">"?ngModel"</span>,<br /> link: <span class="kwrd">function</span> ($scope, element, attributes, modelController) {<br /> <span class="kwrd">if</span> (!modelController)<br /> <span class="kwrd">return</span>;<br /> <span class="rem">// Watch the validity of the input</span><br /> $scope.$watch(<span class="kwrd">function</span> () {<br /> <span class="kwrd">return</span> modelController.$invalid;<br /> }, <span class="kwrd">function</span> () {<br /> <span class="rem">// $emit messages to the control group</span><br /> <span class="kwrd">if</span> (modelController.$invalid) $scope.$emit(<span class="str">"inputError"</span>);<br /> <span class="kwrd">else</span> $scope.$emit(<span class="str">"inputValid"</span>);<br /> });<br /> }<br /> };<br />});</pre><br /><p>It’s name is <font face="Consolas">input</font>. I suggest you make a function first and use it as <font face="Consolas">input, textarea</font> and <font face="Consolas">selectbox</font> directive. That way you can achieve same behaviour on more controls. The directive itself monitors the validity of the model connected to the input–if there is <font face="Consolas">ngModel</font> directive present on the same element. When there’s a change of the validity, it emits a message to the control group. <a href="http://jsfiddle.net/kvetis/Pemat/4/" target="_blank">Check the JSFiddle</a> if you want to see it in action.<br /><p><em>But wait! I don’t want to see the input red just when I haven’t started filling something out!</em> Of course not, so lets check the validity first after the user has left the input. This is how I do it:<pre class="csharpcode"> <span class="kwrd">var</span> hasBeenVisited = <span class="kwrd">false</span>;<br /> <span class="rem">// check if user has left the field</span><br /> element.on(<span class="str">"blur"</span>, <span class="kwrd">function</span> () {<br /> $scope.$apply(<span class="kwrd">function</span> () {<br /> hasBeenVisited = <span class="kwrd">true</span>;<br /> });<br /> });<br /> <span class="rem">// Watch the validity of the input</span><br /> $scope.$watch(<span class="kwrd">function</span> () {<br /> <span class="kwrd">return</span> modelController.$invalid && hasBeenVisited;<br /> }, <span class="kwrd">function</span> () {<br /> <span class="rem">// $emit messages to the control group</span><br /> <span class="kwrd">if</span> (modelController.$invalid && hasBeenVisited)<br> $scope.$emit(<span class="str">"inputError"</span>);<br /> <span class="kwrd">else</span> $scope.$emit(<span class="str">"inputValid"</span>);<br /> });</pre><br /><p>I add a <font face="Consolas">hasBeenVisited</font> variable and change it on “<font face="Consolas">blur</font>” on the <font face="Consolas">element</font>. Notice that I need to wrap it in an<font face="Consolas"> $scope.$apply</font> block because I also <font face="Consolas">$watch</font> it. I need it to be detected during digest. I extended the condition on which I notify the form group that there is an error. Check the <a href="http://jsfiddle.net/kvetis/Pemat/5/" target="_blank">updated JSFiddle</a> to see it live.<br /><p><em>But what if i don’t want the </em><font face="Consolas">formGroup</font><em> directive to have its own scope, because I find it unnecessary and can’t bind primitive types in the form group?</em> I use a directive controller, which is allows the input directive to notify the parent directive about it’s state. This is the code of <font face="Consolas">formGroup</font> directive.<pre class="csharpcode"> <span class="rem">//get the controller in the link function</span><br /> require: <span class="str">"formGroup"</span>,<br /> link: <span class="kwrd">function</span> ($scope, element, attributes, controller) {<br /> <span class="kwrd">var</span> errorList = {};<br /> controller.inputError = <span class="kwrd">function</span> () {<br /> element.addClass(<span class="str">"has-error"</span>);<br /> };<br /> controller.inputValid = <span class="kwrd">function</span> () {<br /> element.removeClass(<span class="str">"has-error"</span>);<br /> };<br /> },<br /> <span class="rem">//the controller is initialized in link function</span><br /> controller: <span class="kwrd">function</span>() {<span class="kwrd">return</span> {};}</pre><br /><p>I removed the <font face="Consolas">scope</font> of the <font face="Consolas">formGroup</font> and instead I specified a function to return a controller object. In the link function I assign two functions to it, both used for notification about input state. To be able to access the <font face="Consolas">controller</font> in the link function, I have to specify the directive name as the <font face="Consolas">require</font> property.<br /><p>Then in the <font face="Consolas">input </font>directive I have to require the <font face="Consolas">formGroup</font> controller and instead of emitting events on <font face="Consolas">$scope</font> I call the controller methods:<pre class="csharpcode"> <span class="rem">//require controlllers of ngModel and parent directive</span><br /> <span class="rem">//formGroup</span><br /> <span class="rem">//they're injected as array parameter of link function</span><br /> require: [<span class="str">"?ngModel"</span>, <span class="str">"^?formGroup"</span>],<br /> link: <span class="kwrd">function</span> ($scope, element, attributes, controllers) {<br /> <span class="kwrd">var</span> modelController = controllers[0];<br /> <span class="kwrd">var</span> formGroupController = controllers[1];<br /> <span class="kwrd">if</span> (!modelController || !formGroupController) <span class="kwrd">return</span>;<br /> <span class="kwrd">var</span> hasBeenVisited = <span class="kwrd">false</span>;<br /> <span class="rem">// check if user has left the field</span><br /> element.on(<span class="str">"blur"</span>, <span class="kwrd">function</span> () {<br /> $scope.$apply(<span class="kwrd">function</span> () {<br /> hasBeenVisited = <span class="kwrd">true</span>;<br /> });<br /> });<br /> <span class="rem">// Watch the validity of the input</span><br /> $scope.$watch(<span class="kwrd">function</span> () {<br /> <span class="kwrd">return</span> modelController.$invalid && hasBeenVisited;<br /> }, <span class="kwrd">function</span> () {<br /> <span class="rem">// notify the control group</span><br /> <span class="kwrd">if</span> (modelController.$invalid && hasBeenVisited) {<br /> formGroupController.inputError();<br /> } <span class="kwrd">else</span> {<br /> formGroupController.inputValid();<br /> }<br /> });<br /> }</pre><br /><p>This is how I add the <font face="Consolas">has-error</font> class to the form group (bootstrap 3) or control group (bootstrap 2). You can try it out in a <a href="http://jsfiddle.net/kvetis/Pemat/6/" target="_blank">JSFiddle.</a><br /><p>Feel free to use the code in your project. Do you have an different approach? Did I miss something? Is anything unclear? Leave a comment! Did you like the post? +1 or share it! Thank you for your contributions.<br /> Martin Večeřahttp://www.blogger.com/profile/15451621886034236096noreply@blogger.com0tag:blogger.com,1999:blog-6015745492606751686.post-11800884402089654132014-01-16T16:17:00.000+01:002014-10-18T19:24:23.425+02:00AngularJS Loading Widget<p><img style="float: left; margin: 0px 14px 0px 0px; display: inline" src="http://blog.thousandeyes.com/wp-content/uploads/2013/05/angularjs.png" width="134" align="left" height="134"></p> <p><strong>UPDATE: Does not work in 1.3.0. Use Interceptors instead.</strong> See <a href="http://www.kvetis.com/2014/10/angular-request-count-loading-widget-ng.html" target="_blank">Angular Request Count & Loading Widget (ng 1.3.0)</a>.</p> <p>When using angular JS, it would be nice to inform the user that some content is being loaded or that there are some pending requests. I found some solutions of how to show this information to user globally. But in most of these cases the code they used wasn’t clean.</p> <p>One of the problem was using <font size="3" face="Consolas">$rootScope</font> to <font size="3" face="Consolas">$broadcast</font> an event informing that the loading has started. Imagine the tons of listeners being notified.</p> <p>Another problem was the use of Request/Response interceptors. Sometimes this was a unreliable solution for a reason I was unable to find.</p> <p>The third problem was usage of <font size="3" face="Consolas">pendingRequests</font> property of <font size="3" face="Consolas">$http</font> service. The documentation states clearly that it should be used for debugging purposes only.</p> <p>Therefore, I decided writing my very first provider to cope with these problems. I register this provider during config phase of the application as a Request/Response transformer. Every single request/response goes through this function.</p> <p>This is how my requestNotification provider looks like:</p> <div class="csharpcode"><pre><span class="lnum"> 1: </span>angular.module(<span class="str">'myApp.services'</span>).provider(</pre><pre><span class="lnum"> 2: </span><span class="str">'requestNotification'</span>, <span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 3: </span> <span class="rem">// This is where we keep subscribed listeners</span></pre><pre><span class="lnum"> 4: </span> <span class="kwrd">var</span> onRequestStartedListeners = [];</pre><pre><span class="lnum"> 5: </span> <span class="kwrd">var</span> onRequestEndedListeners = [];</pre><pre><span class="lnum"> 6: </span> </pre><pre><span class="lnum"> 7: </span> <span class="rem">// This is a utility to easily increment the request count</span></pre><pre><span class="lnum"> 8: </span> <span class="kwrd">var</span> count = 0;</pre><pre><span class="lnum"> 9: </span> <span class="kwrd">var</span> requestCounter = {</pre><pre><span class="lnum"> 10: </span> increment: <span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 11: </span> count++;</pre><pre><span class="lnum"> 12: </span> },</pre><pre><span class="lnum"> 13: </span> decrement: <span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 14: </span> <span class="kwrd">if</span> (count > 0)</pre><pre><span class="lnum"> 15: </span> count--;</pre><pre><span class="lnum"> 16: </span> },</pre><pre><span class="lnum"> 17: </span> getCount: <span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 18: </span> <span class="kwrd">return</span> count;</pre><pre><span class="lnum"> 19: </span> }</pre><pre><span class="lnum"> 20: </span> };</pre><pre><span class="lnum"> 21: </span> <span class="rem">// Subscribe to be notified when request starts</span></pre><pre><span class="lnum"> 22: </span> <span class="kwrd">this</span>.subscribeOnRequestStarted = <span class="kwrd">function</span>(listener) {</pre><pre><span class="lnum"> 23: </span> onRequestStartedListeners.push(listener);</pre><pre><span class="lnum"> 24: </span> };</pre><pre><span class="lnum"> 25: </span> </pre><pre><span class="lnum"> 26: </span> <span class="rem">// Tell the provider, that the request has started.</span></pre><pre><span class="lnum"> 27: </span> <span class="kwrd">this</span>.fireRequestStarted = <span class="kwrd">function</span>(request) {</pre><pre><span class="lnum"> 28: </span> <span class="rem">// Increment the request count</span></pre><pre><span class="lnum"> 29: </span> requestCounter.increment(); </pre><pre><span class="lnum"> 30: </span> <span class="rem">//run each subscribed listener</span></pre><pre><span class="lnum"> 31: </span> angular.forEach(onRequestStartedListeners, <span class="kwrd">function</span>(listener) { </pre><pre><span class="lnum"> 32: </span> <span class="rem">// call the listener with request argument</span></pre><pre><span class="lnum"> 33: </span> listener(request);</pre><pre><span class="lnum"> 34: </span> }); </pre><pre><span class="lnum"> 35: </span> <span class="kwrd">return</span> request;</pre><pre><span class="lnum"> 36: </span> };</pre><pre><span class="lnum"> 37: </span> </pre><pre><span class="lnum"> 38: </span> <span class="rem">// this is a complete analogy to the Request START</span></pre><pre><span class="lnum"> 39: </span> <span class="kwrd">this</span>.subscribeOnRequestEnded = <span class="kwrd">function</span>(listener) {</pre><pre><span class="lnum"> 40: </span> onRequestEndedListeners.push(listener);</pre><pre><span class="lnum"> 41: </span> };</pre><pre><span class="lnum"> 42: </span> </pre><pre><span class="lnum"> 43: </span> </pre><pre><span class="lnum"> 44: </span> <span class="kwrd">this</span>.fireRequestEnded = <span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 45: </span> requestCounter.decrement();</pre><pre><span class="lnum"> 46: </span> <span class="kwrd">var</span> passedArgs = arguments;</pre><pre><span class="lnum"> 47: </span> angular.forEach(onRequestEndedListeners, <span class="kwrd">function</span>(listener) {</pre><pre><span class="lnum"> 48: </span> listener.apply(<span class="kwrd">this</span>, passedArgs);</pre><pre><span class="lnum"> 49: </span> });</pre><pre><span class="lnum"> 50: </span> <span class="kwrd">return</span> arguments[0];</pre><pre><span class="lnum"> 51: </span> };</pre><pre><span class="lnum"> 52: </span> </pre><pre><span class="lnum"> 53: </span> <span class="kwrd">this</span>.getRequestCount = requestCounter.getCount;</pre><pre><span class="lnum"> 54: </span> </pre><pre><span class="lnum"> 55: </span> <span class="rem">//This will be returned as a service</span></pre><pre><span class="lnum"> 56: </span> <span class="kwrd">this</span>.$get = <span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 57: </span> <span class="kwrd">var</span> that = <span class="kwrd">this</span>;</pre><pre><span class="lnum"> 58: </span> <span class="rem">// just pass all the functions</span></pre><pre><span class="lnum"> 59: </span> <span class="kwrd">return</span> {</pre><pre><span class="lnum"> 60: </span> subscribeOnRequestStarted: that.subscribeOnRequestStarted,</pre><pre><span class="lnum"> 61: </span> subscribeOnRequestEnded: that.subscribeOnRequestEnded,</pre><pre><span class="lnum"> 62: </span> fireRequestEnded: that.fireRequestEnded,</pre><pre><span class="lnum"> 63: </span> fireRequestStarted: that.fireRequestStarted,</pre><pre><span class="lnum"> 64: </span> getRequestCount: that.getRequestCount</pre><pre><span class="lnum"> 65: </span> };</pre><pre><span class="lnum"> 66: </span> };</pre><pre><span class="lnum"> 67: </span>}</pre><pre><span class="lnum"> 68: </span>);</pre></div><br /><style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style><br /><br /><p>The provider methods (<font size="3" face="Consolas"><font color="#4f81bd">this</font>.someFunction</font>) can be accessed during the configuration phase of the application. So I add the request/response transformers:</p><br /><div class="csharpcode"><pre><span class="lnum"> 1: </span>angular.module(<span class="str">'myApp'</span>, [</pre><pre><span class="lnum"> 2: </span> <span class="str">'ngRoute'</span>,</pre><pre><span class="lnum"> 3: </span> <span class="str">'myApp.filters'</span>,</pre><pre><span class="lnum"> 4: </span> <span class="str">'myApp.services'</span>,</pre><pre><span class="lnum"> 5: </span> <span class="str">'myApp.directives'</span>,</pre><pre><span class="lnum"> 6: </span> <span class="str">'myApp.controllers'</span></pre><pre><span class="lnum"> 7: </span>])</pre><pre><span class="lnum"> 8: </span> .config(<span class="kwrd">function</span>(</pre><pre><span class="lnum"> 9: </span> $httpProvider,</pre><pre><span class="lnum"> 10: </span> requestNotificationProvider) {</pre><pre><span class="lnum"> 11: </span> $httpProvider</pre><pre><span class="lnum"> 12: </span> .defaults</pre><pre><span class="lnum"> 13: </span> .transformRequest</pre><pre><span class="lnum"> 14: </span> .push(<span class="kwrd">function</span>(data) {</pre><pre><span class="lnum"> 15: </span> requestNotificationProvider</pre><pre><span class="lnum"> 16: </span> .fireRequestStarted(data);</pre><pre><span class="lnum"> 17: </span> <span class="kwrd">return</span> data;</pre><pre><span class="lnum"> 18: </span> });</pre><pre><span class="lnum"> 19: </span> </pre><pre><span class="lnum"> 20: </span> $httpProvider</pre><pre><span class="lnum"> 21: </span> .defaults</pre><pre><span class="lnum"> 22: </span> .transformResponse</pre><pre><span class="lnum"> 23: </span> .push(<span class="kwrd">function</span>(data) {</pre><pre><span class="lnum"> 24: </span> requestNotificationProvider</pre><pre><span class="lnum"> 25: </span> .fireRequestEnded(data);</pre><pre><span class="lnum"> 26: </span> <span class="kwrd">return</span> data;</pre><pre><span class="lnum"> 27: </span> });</pre><pre><span class="lnum"> 28: </span> });</pre></div><br /><p>Finally, I create a directive which listens onRequestStarted/Ended. It shows/hides the element with the directive accordingly. You can place a nice animated gif to indicate a pending request.</p><br /><div class="csharpcode"><pre><span class="lnum"> 1: </span>angular.module(<span class="str">'myApp.directives'</span>)</pre><pre><span class="lnum"> 2: </span> .directive(<span class="str">'loadingWidget'</span>, <span class="kwrd">function</span> (requestNotification) {</pre><pre><span class="lnum"> 3: </span> <span class="kwrd">return</span> {</pre><pre><span class="lnum"> 4: </span> restrict: <span class="str">"AC"</span>,</pre><pre><span class="lnum"> 5: </span> link: <span class="kwrd">function</span> (scope, element) {</pre><pre><span class="lnum"> 6: </span> <span class="rem">// hide the element initially</span></pre><pre><span class="lnum"> 7: </span> element.hide();</pre><pre><span class="lnum"> 8: </span> </pre><pre><span class="lnum"> 9: </span> <span class="rem">//subscribe to listen when a request starts</span></pre><pre><span class="lnum"> 10: </span> requestNotification</pre><pre><span class="lnum"> 11: </span> .subscribeOnRequestStarted(<span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 12: </span> <span class="rem">// show the spinner!</span></pre><pre><span class="lnum"> 13: </span> element.show();</pre><pre><span class="lnum"> 14: </span> });</pre><pre><span class="lnum"> 15: </span> </pre><pre><span class="lnum"> 16: </span> requestNotification</pre><pre><span class="lnum"> 17: </span> .subscribeOnRequestEnded(<span class="kwrd">function</span>() {</pre><pre><span class="lnum"> 18: </span> <span class="rem">// hide the spinner if there are no more pending requests</span></pre><pre><span class="lnum"> 19: </span> <span class="kwrd">if</span> (requestNotification.getRequestCount() === 0)</pre><pre><span class="lnum"> 20: </span> element.hide();</pre><pre><span class="lnum"> 21: </span> });</pre><pre><span class="lnum"> 22: </span> }</pre><pre><span class="lnum"> 23: </span> };</pre><pre><span class="lnum"> 24: </span> });</pre></div><br /><p>Note that <font size="3" face="Consolas">requestNotificationProvider</font> has become a service to use by the directive, thus its injected as <font size="3" face="Consolas">requestNotification</font>. We can access all the methods of the object returned by the <font size="3" face="Consolas">$get</font> function.</p><br /><h2>Demo</h2><br /><p>See the <a href="http://jsfiddle.net/A6vgG/2/" target="_blank">attached JSFiddle</a> for a demonstration of how it works.</p><br /><p>Feel free to use the code in your projects. If you liked this post, like & share it. Or give me a Flattr.</p><br /><p>And how do you do it? See a bug in my code? Do you have a different approach? Leave a comment!</p> Martin Večeřahttp://www.blogger.com/profile/15451621886034236096noreply@blogger.com0