block-ui-pattern has no effect - angularjs

i am trying to implement block-ui into our angular application on an element by element basis. (everything is included, referenced and injected correctly)
We have been trying to implement
block-ui-pattern
with no success.
our $http request is :-
$http.get('/user/123/GetUserAddress/').then(function (data) {
and our block-ui-pattern is :-
< div block-ui block-ui-pattern="/^user\/123\/GetUserAddress\$/">
{{address}}
</div>
This seems to match the documentation, but is failing to work. Am i missing something fundamental?
Our application exposes an isloading flag. initially set to true, and when the $http promise returns, sets this to false.. I realize that it is not in the documentation, however, Is there a way to set
< div block-ui="isloading"></div>

Post by Parash Gami pointed me in the right direction.
I actually ended up writing a custom directive that wraps block-ui
var myBlocker = angular.module('app.Angular.Directive.myBlocker ', []);
myBlocker.directive('myBlocker ', ['$compile', function ($compile) {
return {
restrict: 'A',
scope :{
blockId: '#id',
block: '=',
},
controller: ['$scope', 'blockUI', function ($scope, blockUI) {
var myBlock = blockUI.instances.get($scope.blockId);
$scope.$watch('block', function (newValue, oldValue) {
if ($scope.block === true)
{
myBlock.start()
}
else {
myBlock.stop()
}
});
}],
link: function link(scope, element, attrs) {
element.attr('block-ui', scope.blockId);
element.attr('style', 'min-height:200px;');
element.removeAttr("my-blocker");
element.removeAttr("data-my-blocker");
$compile(element)(scope);
}
};
}]);
This allows me to now simply add the directive to an element
< div id="myId" my-blocker block="loading">

Please check sample code. Just include one CSS and one JS of blockUI and add dependency blockUI, use blockUI.start() method to show loader and use blockUI.stop() method to hide loader. Following example hide loader after 2 seconds. Use it as per your requirement.
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="http://angular-block-ui.nullest.com/angular-block-ui/angular-block-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
<script type="text/javascript" src="http://angular-block-ui.nullest.com/angular-block-ui/angular-block-ui.js"></script>
</head>
<body ng-app="app.user">
<div ng-controller="tempController">
</div>
</body>
</html>
<script type="text/javascript">
var app = angular.module('app.user',['blockUI']);
app.controller('tempController', function(blockUI,$timeout)
{
blockUI.start();
$timeout(function()
{
blockUI.stop();
},2000)
});
</script>

Related

How can an Angular directive compile() function access an isolated scope?

I have the following directive:
angular.module("example_module", [])
.directive("mydirective", function() {
return {
scope: { data: "#mydirective" }
compile: function(element) {
element.html('{{example}}');
return function($scope) {
$scope.example = $scope.data + "!";
};
}
};
});
and the following HTML code:
<!DOCTYPE html>
<html ng-app="example_module">
<head>
<meta charset="utf-8">
<title>Example title</title>
<script src="lib/angular/angular.min.js"></script>
<script src="js/example.js"></script>
</head>
<body>
<div mydirective="Hello world"></div>
</body>
</html>
I would expect the directive to compile to Hello world!, but it compiles to an empty string instead. scope creates an isolated scope which seems impossible to reach for {{example}}.
I would like to know how the new HTML code created by compile() can access the link function $scope.
This doesn't work because {{example}} is being evaluated against the parent scope, which makes sense, since you are essentially changing the element before compilation to:
<div>{{example}}<div>
You can verify by replacing '$scope.example =' with '$scope.$parent.example =' (for demonstration purposes only - it's not a best practice to use $parent).
What you are really trying to do is something similar to transclusion, but there are very easier ways to do it. For instance:
angular.module("example_module", [])
.directive("mydirective", function() {
return {
restrict: 'A',
scope: { data: "#mydirective" },
template: '{{example}}',
compile: function(element) {
return function($scope) {
console.log($scope.data);
$scope.example = $scope.data + "!";
console.log($scope.example);
};
}
};
});
When you use a template, it replaces the content of the element the directive is applied to (unless you use replace: true, in which case it replaces the entire element), and the contents of the template are evaluated against the directive scope.
You could do what you are trying to do using the transclude parameter passed to compile (see the docs), but this has been deprecated so I wouldn't recommend going down that road.
Here's a Plunk where you can play with some variations.

AngularJS: Binding JavaScript Received in XHR to the View

Working on a reporting application where reports are generated (in HTML) from a BIRT Report Engine object. The report data comes as a JSON string is recieved from XHR. The JSON string contains a combination of HTML and javascript (a function call, specifically). Once received, the report data is stuffed into a for display in the view. The view is put together using AngularJS.
I did some research and found that binding the HTML/javascript to the view in Angular requires the use of $compile. Using that as a basis, i put together some code that will include data and execute code bound from a string defined explicitly in the $scope. But - unless i'm going overlooking something after staring at the same stuff for a couple hours, the approach i'm using does not work with $scope data defined by XHR. Here's a plunkr to show the general idea implemented. Any suggestions would be greatly appreciated.
The HTML
<!DOCTYPE html>
<html data-ng-app="example">
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.11.0/ui-bootstrap-tpls.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-sanitize.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="controller" >
<h1>Static Content</h1>
<p><button href="javascript: void(null)" role="link" ng-click="loadSubreport('recv_po_detail.rptdesign', 'static')">PO000007</button></p>
<h1>HTML from static string</h1>
<div compile="snippet"></div>
<h1>HTML from server string</h1>
<div compile="html.body"></div>
<hr />
<button ng-click="alert()">Show XHR Data</button>
</body>
</html>
The Javascript
var app = angular.module('example', []);
app.controller('controller', ['$scope', '$compile', '$http', function ($scope, $compile, $http){
$scope.snippet="<p><button href=\"javascript: void(null)\" ng-click=\"loadSubreport('recv_po_detail.rptdesign', 'compiled')\">PO000007</button></p>";
$http.get('data.json')
.success(function (data) {
$scope.html = data;
});
$scope.loadSubreport = function (filename, source) {
alert("Called from " + source);
};
$scope.alert = function () {{
alert($scope.html.body);
}}
}]);
app.directive('compile', ['$compile', function ($compile) {
"use strict";
return function (scope, element, attrs) {
var ensureCompileRunsOnce = scope.$watch(
function (scope) {
return scope.$eval(attrs.compile);
},
function (value) {
element.html(value);
$compile(element.contents())(scope);
ensureCompileRunsOnce();
}
);
};
}]);
Your watch goes off right at the start, when html.body still is undefined.
Then you run ensureCompileRunsOnce() and unwatch the scope. So the proper report, once loaded, never gets compiled.
I uncommented the line ensureCompileRunsOnce() and get a nice view of the report.
DEMO

Angular animation directive should call controller function after animation has finished

I'm trying to write an animation directive, that changes the width of an element and makes a change in the model afterwords. Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp" ng-controller="MyCtrl">
<button ng-init="speed=20000" ng-click="model.width = model.width + 100;"> + </button>
<button ng-click="model.width = model.width - 100;"> - </button>
<div animate-to-width="model.width" speed="{{speed}}" done="model.done()" style="background-color: #f00; width: 100px;">w:{{model.width}}|a:{{model.a}}|b:{{model.b}}</div>
</div>
<script src="components/jquery/jquery.js"></script>
<script src="components/angular-unstable/angular.js"></script>
<script>
var myApp = angular.module('myApp',[]);
myApp.directive('animateToWidth', function() {
return {
'restrict': 'A',
'link' : {
'post': function(scope, element, attrs) {
scope.$watch(
attrs.animateToWidth,
function (newValue) {
element.animate(
{'width': newValue + 'px'},
attrs.speed,
function () {
scope.model.a++;
//scope[attrs.done]();
}
);
}
);
}
}
};
});
function MyCtrl($scope) {
$scope.model = {};
$scope.model.width = 100;
$scope.model.a = 0;
$scope.model.b = 0;
$scope.model.done = function () { $scope.model.b++; };
}
</script>
</body>
</html>
When I run this code the second parameter of the jQuery .animate() function seems not to affect the animation speeds and the callback (third parameter) will be called immediately instead after the animation has been finished.
My second problem is, that I would want to pass a callback from the controller into the directive and I don't know how to achieve this.
EDIT
Here is the solution (thanks to #banana-in-black):
http://plnkr.co/edit/D9TJHBYjtnxTve0xZpBS?p=preview
And here without those width values in the controller:
http://plnkr.co/edit/eiy99Crh57Jc78RhAsRt?p=preview
What you get from attrs.speed is String, and there's no effect if you set duration as String to jQuery.animate(). So make it a Number could solve the speed issue.
The callback after jQuery.animate() is called outside "the angular world", so you have to use $apply to make sure angular knows what happened to models.
If you didn't assign scope to directive, it will use the existing scope on the element. In this case, the div[animate-to-width] uses the same scope as MyCtrl does. You can just call your function which is set to scope in your controller.
scope.$watch(
attrs.animateToWidth,
function (newValue) {
element.animate(
{'width': newValue + 'px'},
attrs.speed * 1,
function () {
scope.$apply(function() {
scope.model.a++;
scope.model.done();
});
}
);
}
);
Example in Plunker

AngularJS - how to override directive ngClick

I want to override directive ng-click: to some make some $rootscope changes before each execution of ng-click. How to do it?
Every directive is a special service inside AngularJS, you can override or modify any service in AngularJS, including directive
For example remove built-in ngClick
angular.module('yourmodule',[]).config(function($provide){
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
//$delegate is array of all ng-click directive
//in this case first one is angular buildin ng-click
//so we remove it.
$delegate.shift();
return $delegate;
}]);
});
angular support multiple directives to the same name so you can register you own ngClick Directive
angular.module('yourmodule',[]).directive('ngClick',function (){
return {
restrict : 'A',
replace : false,
link : function(scope,el,attrs){
el.bind('click',function(e){
alert('do you feeling lucky');
});
}
}
});
check out http://plnkr.co/edit/U2nlcA?p=preview
I wrote a sample that removed angular built-in ng-click and add a customized ngClick
You can't override AngularJS built-in directives. However, you can define multiple directives with the same name and have them executed against the same element. By assigning appropriate priority to your directive, you can then control whether your directive runs before or after a built-in directive.
This plunker shows how to build an ng-click directive that executes before the built-in ng-click does. The code is also shown below. When clicking the link, the custom ng-click will run first, then the built-in ng-click does.
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="jquery#1.9.0" data-semver="1.9.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.js"></script>
<script data-require="angular.js#1.0.7" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="MyCtrl">
<a ng-click="alert()">Click me</a>
</body>
</html>
script.js
angular.module('app', [])
.directive('ngClick', function($rootScope) {
return {
restrict: 'A',
priority: 100, // give it higher priority than built-in ng-click
link: function(scope, element, attr) {
element.bind('click', function() {
// do something with $rootScope here, as your question asks for that
alert('overridden');
})
}
}
})
.controller('MyCtrl', function($scope) {
$scope.alert = function() {
alert('built-in!')
}
})

Getting MathJax to update after changes to AngularJS model

I am trying to use AngularJS two-way binding text which includes Latex style equations. I would like to call MathJax to format the equations, but I'm not sure of the best way to ensure that MathJax is called after AngularJS finishes changing the model. I think I need a callback. Here is my JavaScript:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.Update = function() {
$scope.Expression = 'Evaluate: \\( \\frac{9}{4} \\div \\frac{1}{6} \\)';
MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
}
$scope.Expression = 'Evaluate: \\( \\frac{5}{4} \\div \\frac{1}{6} \\)';
}
And here is my HTML:
<div ng-controller="MyCtrl">
<button ng-click="Update()">Update</button>
{{Expression}}
</div>
Fiddle is here: http://jsfiddle.net/LukasHalim/UVjTD/1/. You'll notice that on the fiddle the original expression isn't removed even after you click the update button twice - seems like a bug or conflict.
Having wasted many days (and maybe weeks) fighting MathJax, I'm all too familiar with its various quirks with updating math expressions on the fly. I'm brand new to Angular but this gave me a good chance to dive in and I ended up with a solution which solves my problems -- hopefully it'll solve yours as well.
Live demo: jsfiddle
Instead of using the plain interpolation that Angular provides, I created a new directive based on ng-bind called mathjax-bind.
If expression is a variable containing math code, then instead of \( {{expression}} \) you can write:
<span mathjax-bind="expression"></span>
and everything will be typeset and updated at the appropriate times.
The supporting code for the directive follows:
myApp.directive("mathjaxBind", function() {
return {
restrict: "A",
controller: ["$scope", "$element", "$attrs",
function($scope, $element, $attrs) {
$scope.$watch($attrs.mathjaxBind, function(texExpression) {
var texScript = angular.element("<script type='math/tex'>")
.html(texExpression ? texExpression : "");
$element.html("");
$element.append(texScript);
MathJax.Hub.Queue(["Reprocess", MathJax.Hub, $element[0]]);
});
}]
};
});
Simplest, fastest and most stable solution:
$rootScope.$watch(function(){
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
return true;
});
Advantages:
Easy to setup, just copy this code.
Everything on your page is typeset.
It renders much faster than the other solutions. This is because it can render the page in one go. Other answers here wait for one item to finish, until they typeset the next one. That makes rendering veeeery slow if there are for example multiple mathjax-bind directives (as another answer suggests). This point is the reason I was looking for a different answer.
You can still easily exclude elements using the option “ignoreClass” in your mathjax settings.
Benchmarking:
100 mathjax-bind directives took 63 seconds, while with this method it took 1.5 second to render the page. I know that this function will be executed a lot since it's called on every digest cycle, however, it doesn't noticeably slow down the page.
I created a simple fiddle expanding on Ben Alpert's answer. Here's the fiddle and plunk.
Specifically If a text has only a part of it to be converted by Mathjax, you can use this.
For inline mathjax you must surround the text by $, and for block display you must surround the block by $$. (You can use any format you like if you create the corresponding regex)
app.js
MathJax.Hub.Config({
skipStartupTypeset: true,
messageStyle: "none",
"HTML-CSS": {
showMathMenu: false
}
});
MathJax.Hub.Configured();
var myApp = angular.module("myApp", []);
myApp.directive("mathjaxBind", function() {
return {
restrict: "A",
scope:{
text: "#mathjaxBind"
},
controller: ["$scope", "$element", "$attrs", function($scope, $element, $attrs) {
$scope.$watch('text', function(value) {
var $script = angular.element("<script type='math/tex'>")
.html(value == undefined ? "" : value);
$element.html("");
$element.append($script);
MathJax.Hub.Queue(["Reprocess", MathJax.Hub, $element[0]]);
});
}]
};
});
myApp.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
html = html.replace(/\$\$([^$]+)\$\$/g, "<span class=\"blue\" mathjax-bind=\"$1\"></span>");
html = html.replace(/\$([^$]+)\$/g, "<span class=\"red\" mathjax-bind=\"$1\"></span>");
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
function MyCtrl($scope, $element) {
$scope.html = "A coin of is $ \\frac{5}{4} $ thrown $$\\frac{1}{6}$$ dfv";
}
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML&delayStartupUntil=configured&dummy=.js"></script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="http://code.angularjs.org/1.2.7/angular.js" data-semver="1.2.7"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="MyCtrl">
<input type="text" ng-model="html"/><br/>
<div dynamic="html"></div>
</div>
</body>
style.css
input[type="text"] {
width: 800px;
}
.red{
color:red;
display:inline-block;
}
.blue{
color:blue;
display:block;
}
Take a look at http://jsfiddle.net/pz5Jc/
In your template:
{{Label}} <span id="mathElement">{{Expression}}</span>
In your controller:
$scope.Update = function() {
$scope.Expression = '\\frac{9}{4} \\div \\frac{1}{6}';
$scope.Label = 'Updated Expression:'
var math = MathJax.Hub.getAllJax("mathElement")[0];
math.Text('\\frac{4}{4} \\div \\frac{2}{6}');
}
Couple of points:
I'm not too familiar with mathjax, but:
Splitting the label out from the expression allows you to work with the expression directly.
You need to manually pick up a DOM element to force a refresh of the expression. This isn't a very 'angular' way to do things unfortunately - but when mathjax parses the expression (and inserts it's own DOM elements), it pushes those elements outside the angular bindings.
Fix here is to specifically select the correct mathjax element and call a text change function to update the expression.
Here's a directive that lets you use double curly markup inside the expression (and doesn't require setting an expression variable on the scope). It's based on this blog post, except I only support MathJax, and I save the compiled DOM, so that it updates on changes to scope variables.
As Alex Osborn said, it's best to separate non-math from math.
Usage:
<p>This is inline math: <latex>x^{ {{power}} }</latex>,
and this is display math: <div latex> y^{ {{power}} } .</div></p>
In a snippet:
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.power = "\\sin(x^2)";
})
.directive('latex', function() {
return {
restrict: 'AE',
link: function(scope, element) {
var newDom = element.clone();
element.replaceWith(newDom);
var pre = "\\(",
post = "\\)";
if (element[0].tagName === 'DIV') {
pre = "\\[";
post = "\\]";
}
scope.$watch(function() {
return element.html();
}, function() {
console.log(element);
newDom.html(pre + element.html() + post);
MathJax.Hub.Typeset(newDom[0]);
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<div ng-app="app" ng-controller="ctrl">
<p>Power:
<input ng-model="power" />
</p>
<p>This is the inline latex,
<latex>x^{ {{power}} }</latex>, followed by some display mode latex
<div latex>y^{ {{power}} } = {{power}}.</div>And that's it!
</p>
</div>
A simple solution is to use $timeout to put MathJax.Hub.Queue(["Typeset", MathJax.Hub]) in the browser event queue (see Run a directive after the DOM has finished rendering).
Something like this:
var app = angular.module('myApp', []);
app.controller('myController', function ($scope, $timeout) {
controller = this;
$scope.Update = function () {
$scope.value = " \\( \\frac{5}{4} \\div \\frac{1}{6} \\)";
$timeout(controller.updateMathJax, 0);
}
this.updateMathJax = function () {
MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
}
});
You can try with my modifications http://jsfiddle.net/bmma8/4/
modify input or click on button will update your expression.
js:
MathJax.Hub.Config({
extensions: ["tex2jax.js"],
jax: ["input/TeX","output/HTML-CSS"],
tex2jax: {inlineMath: [["$","$"],["\\(","\\)"]]}
});
var myApp = angular.module('myApp',[]);
function MyCtrl($scope, $log) {
var QUEUE = MathJax.Hub.queue; // shorthand for the queue
$scope.Update = function() {
QUEUE.Push(["Text",MathJax.Hub.getAllJax("MathOutput")[0],"\\displaystyle{"+ $scope.Expression+"}"]);
//$scope.Expression = 'Updated Expression: \\( \\frac{9}{4} \\div \\frac{1}{6} \\)';
//MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
}
$scope.Expression = 'Original Expression: \\( \\frac{5}{4} \\div \\fra
and html:
<div ng-controller="MyCtrl">
<button ng-click="Update()">Update</button>
<input ng-model="Expression" ng-change="Update()">
<div id="MathOutput">
You typed: ${}$
</div>
</div>
Alexandre
I actually thought of another solution. When you render some angular and math you do this:
ANGULAR CONTROLLER
$scope x = 5;
HTML
<h3> {{ '$ Multiplication = '+ x + ' * 2 =' + (x*2) + '$'}} </h3>
Formated Math Jax result
Multiplication = 5 * 2 = 10
The key is to include the dollar signs inside the brackets as text. When Angular renders them, the dollar signs will appear as plain text, but when the Math Jax format comes into action it will recognize the dollar signs and do the magic.
I Build a directive for this....
FIDDLE: http://jsfiddle.net/8YkUS/1/
HTML
p data-math-exp data-value="math">
JAVASCRIPT
appFlipped.directive("mathExp", function () {
return {
scope: {
value: "="
},
link: function (scope, el) {
var domEl = el[0];
scope.$watch("value", function (newValue) {
//nothing to do here
if (newValue == null || window.MathJax == null)return;
//update the dom with the new value and pass the hub for styling the equation
domEl.innerHTML = '`' + newValue + '`';
MathJax.Hub.Queue(["Typeset", MathJax.Hub, domEl]);
});
}
}
});
I fiddled a bit more on Roney's solution. The display math should be displayed in display mode; with
<script type="math/tex; mode=display">
I added an attribute to the generated span to indicate that.
Fiddle is here http://jsfiddle.net/repa/aheujhfq/8/

Resources