Adding html in a directive that contains directives - angularjs

HTML
<div show-orders ng-click="showOrderDetails()" ></div>
Javascript
var ddApp = angular.module('ddApp', []);
ddApp.directive('showOrders', [function ($compile)
{
return {
link: function (scope, element, attrs)
{
scope.showOrderDetails = function ()
{
// How I would normally insert HTML.
element.append('<div order-details>Some text</div>');
// How do you use $compile here???
//el = $compile(tpl)(scope);
}
}
};
} ]);
ddApp.directive('orderDetails', [function ()
{
return {
link: function (scope, element, attrs)
{
// Do something
}
};
} ]);
When you click on the div, the showOrderDetails gets called. I then want to append some html to the div (i.e., insert it into the div). However, the html that I am inserting is a div containing another directive called order-details. How do I compile this html and insert it into the div so that Angular is aware of the order-details directive?
Another question. I'm not sure if placing the html code directly within the click event is the right solution. What if I wanted to have this come from some template, so that I could reuse the template elsewhere. Is it possible to load the html from a service or factory? If so, how? Is this the answer:
https://stackoverflow.com/a/15573493/753632

var template='<div order-details>Some text</div>'
element.append($compile(template)(scope));
yes it possible to load template using services
$http({method: 'GET', url: '/views/template'})
.success(function(data){
element.append($compile(data)(scope));
});

Related

Run document.ready with angularjs routes

I am trying to run the function .parallax() from Materialize framework using routes in the angularjs. I already config the command document.ready for each template but this doesn't work. This works just in the first time. What is the best way to make document.ready calling functions like $('.test').test(); using routes? I will wait! Thanks!
Template HTML of my route:
<!-- JS -->
<script type="text/javascript">
$(document).ready(function(){
$('.parallax').parallax(); //Run just in the first time
};
</script>
<!-- Template -->
<div class="" ng-controller="homeCtrl">
...
</div>
Controller:
app.controller('homeCtrl', ['$scope', function($scope){
//Ready
angular.element(document).ready(function() {
$('.parallax').parallax(); // Doesn't work
});
}]);
Thanks!
Obviously the code in controller will not work as this is a single page application and by the time the controller is loaded the document is already loaded and the call back in the script tag is called. I think you can create a directive like
App.directive('testJquery', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$(element).parallex();
}
};
});
and the html be like, assuming your parallex class elements are present in each view of the routes
<div class="parallex" test-plugin><div>
If there is one div which is outside the ng-view and you want to call the parallex or any testFuntion on the element every time you change route then what you can do in your main controller(under which this element is there)
Change the directive to
App.directive('testJquery', function() {
return {
restrict: 'A',
scope:{
runFunctionAgain:'='
},
link: function(scope, element, attrs) {
$(element).parallex();
scope.$watch('runFunctionAgain', function(){
if(scope.runFunctionAgain){
$(element).parallex();
scope.runFunctionAgain = false;
}
})
}
};
});
And take the parameter from the controller in the directive
<div class="parallex" run-function-again="runFunctionAgain" test-plugin><div>
In the controller
scope.runFunctionAgain = true;
$scope.$on('$routeChangeStart', function (event, next, current) {
scope.runFunctionAgain = true;
});

attribute directive that adds element to the dom from a template file

i have a template file myfile.html and i'm writing an attribute directive in angular, the purpose of this directive is to insert the elements that are inside myfile.html after the element that the directive attribute was declared on. for example: will insert all the content of myfile.html after that div.
i tried to do it like so:
app.directive('myAngularDirective', function () {
return {
restrict: "A",
link: function(scope, element){
var addMe = angular.element("myfile.html");
element.after($copile(addMe));
scope.$apply();
}
}
});
<h1>myfile.html</h1>
<div ng-controller="myController">
<div ng-click=clickMe()></div>
</div>
<h1>my home page</h1>
<div my-angular-directive></div>
but nothing happens, the content of myfile.html is not added to the home page.
if i write plain html in the after function like so:
element.after("")
it does get added to the dom but angular do not digest it, and ng-click is not working.
thanks for your help.
$compile("<html here>") returns a template function that expects a scope to be passed before you get your DOM back. Change your code to the following and it should work as expected:
app.directive('myAngularDirective', function($compile) {
return {
restrict: "A",
link: function(scope, element){
var addMe = angular.element("<div>Hello World</div>");
element.after($compile(addMe)(scope));
scope.$apply();
}
}
});
If you want to load the template from an external URL. You'll need to do a template request.
app.directive('myAngularDirective', function($compile,$templateRequest) {
return {
restrict: "A",
link: function(scope, element){
$templateRequest('index.html').then(function(tpl){
var addMe = angular.element(tpl);
element.after($compile(addMe)(scope));
scope.$apply();
});
}
}
});

Angular how to change controller scope from onclick directive

Here is my directive
.directive('closeMapMessage', function($log) {
'use strict';
return function(scope, element) {
var clickingCallback = function() {
angular.element('.map').fadeOut("slow");
};
element.bind('click', clickingCallback);
};
})
How can I change a scope variable in the controller ?
<div class="msg-mobile" ng-show="showInstructionModal">
<div class="close-map-msg ok-got-it-footer" close-map-message>Ok, got it. </div>
</div>
I basically want to set my showInstructionModalfalse when my close directive is called.
From the current snippet of code, it's hard to tell why you're not using a modal solution tailored for Angular, i.e. AngularUI's modal.
However, in your current code, you're attaching a click event to the element outside of Angular's awareness. That's why clicking on the element will not have effect until the next $digest cycle has run. Also, in Agular you normally don't use directives the way you're trying to do. I would suggest updating the directive to also provide the HTML and then use the ng-clickattribute to attach the event handler via Angular.
Update your directive's code to:
.directive('closeMapMessage', function($log) {
'use strict';
return {
restrict: "AE",
link: function(scope, element) {
scope.closeModal = function() {
angular.element('.map').fadeOut("slow");
scope.showInstructionModal = false; // probably need to put this in a $timeout for example to show the fading of the element
};
},
template: '<div class="close-map-msg ok-got-it-footer" ng-click="closeModal()">Ok, got it.</div>'
};
})
And then update your HTML accordingly:
<div class="msg-mobile" ng-show="showInstructionModal">
<close-map-message></close-map-message>
</div>
You should run digest cycle manually after click event occurrence to update all scope bindings
.directive('closeMapMessage', function($log) {
'use strict';
return function(scope, element) {
var clickingCallback = function() {
angular.element('.map').fadeOut("slow");
scope.$apply();
};
element.bind('click', clickingCallback);
};
})

How to call custom directive template url on button click using AngularJS

I am trying to call a html page which is given in the templateUrl of my directive when I click a button, below is my code "hi" should be displayed when I click the "click me" button. Please suggest me how to do this.
sample.html:
<div ng-controller="MyController">
<button custom-click="">Click Me</button>
</div>
sample.js:
appRoot.directive('customClick', function() {
return {
link: function(scope, element, attrs) {
element.click(function(){
templateUrl:'/page.html';
});
}
}
});
Page.html:
<div><h4>HI</h4></div>
Update: The Snippet has been updated with getting the code from a URL
Adding onto the above answers:
appRoot.directive('customClick', function($http, $compile) {
return {
link: function(scope, element, attrs) {
element.click(function(){
$http.get("/page.html").then(function(resp){
$(element).html(resp.data);
var fnLink = $compile(element);
fnLink($scope);
});
});
}
}
});
P.S: Needs jQuery to run as using some functions like html() which can be bypassed if you dont want to include jQuery
I don't think that structure is possible, at all.
The easiest way would be to handle a show/hide type of functionality on the directive and have the template be there at all times.
For this you could use either ng-show, ng-hide or ng-if (and some others that I won't dig into).
base directive
appRoot.directive('customClick', function () {
return {
template: '<div><h5>HI</h5></div>',
link: function (scope, el, attrs) {
scope.active = false;
el.on('click', function () {
scope.$apply(function () {
scope.active = !scope.active;
});
});
}
}
});
ng-show
template: '<div ng-show="active"><h5>HI</h5></div>'
ng-hide
template: '<div ng-hide="!active"><h5>HI</h5></div>'
ng-if
template: '<div ng-if="active"><h5>HI</h5></div>'
Edit: If you are using templateUrl, simply put the ng-show/hide/if directive on the root element of the template being referenced, and this should work the same.
Oh, and here's a fiddle.
http://jsfiddle.net/ADukg/5426/

How to pass async data from directive to controller?

I want to compile a third-party api (uploadcare) to a directive.
The api will return the data info after uploaded in async then I want to do something with the return data in my controller but I have to idea how to pass the return data from directive to controller. Below is my code.
in js
link: function (scope, element, attrs) {
//var fileEl = document.getElementById('testing');
var a = function() {
var file = uploadcare.fileFrom('event', {target: fileEl});
file.done(function(fileInfo) {
//scope.$apply(attrs.directUpload)
//HERE IS MY PROBLEM.
//How can I get the fileInfo then pass and run it at attrs.directUpload
}).fail(function(error, fileInfo) {
}).progress(function(uploadInfo) {
//Show progress bar then update to node
console.log(uploadInfo);
});
};
element.bind('change', function() {a()});
}
in html
<input type="file" direct-upload="doSomething()">
in controller
$scope.doSomething = function() {alert(fileInfo)};
AngularJS allows to execute expression in $parent context with specified values, in your case doSomething().
Here's what you need to do that:
In directive definition, mark directUpload as expression:
scope: {
directUpload: "&"
}
In done callback, call:
scope.directUpload({fileInfo: fileInfo})
Update markup:
<input type="file" direct-upload="doSomething(fileInfo)">
To summorize: scope.directUpload is now a callback, which executes expression inside attribute with specifeid values. This way you can pass anything into controller's doSomething.
Read $compile docs for detailed explanation and examples.
Example you might find useful:
angular
.module("app", [])
.directive("onDone", function ($timeout) {
function link (scope, el, attr) {
$timeout(function () {
scope.onDone({
value: "something"
});
}, 3000)
}
return {
link: link,
scope: {
onDone: "&"
}
}
})
.controller("ctrl", function ($scope) {
$scope.doneValue = "nothing";
$scope.done = function (value) {
$scope.doneValue = value;
};
})
<body ng-controller="ctrl">
Waiting 3000ms
<br>
<div on-done="done(value)">
Done: {{doneValue}}
</div>
</body>
You can pass through an object to the scope of the directive using = within the directive to do two way data binding. This way you can make updates to the data within the directive on the object and it will be reflected in it's original location in the controller. In the controller you can then use $scope.watch to see when the data is changed by the directive.
Something like
http://plnkr.co/edit/gQeGzkedu5kObsmFISoH
// Code goes here
angular.module("myApp",[]).controller("MyCtrl", function($scope){
$scope.something = {value:"some string"}
}).directive("simpleDirective", function(){
return {
restrict:"E",
scope:{someData:"="},
template:"<button ng-click='changeData()'>this is something different</button>",
link: function(scope, iElem, iAttrs){
scope.changeData=function(){
scope.someData.value = "something else";
}
}
}
});

Resources