Dynamically change the action of href using angularjs - angularjs

I'm a newbie to angular, and I'm playing around with it to try and understand how things work. I have an href as part of the template of a directive and an action associated with clicking the link. I would like to know how I can change the action when the user clicks on the link. I tried using a link function in my template, but I couldn't even get it to fire a message to the console.
Here is my link function:
var linkFunction = function(scope) {
scope.$watch(scope.loggedin, function() {
console.log('Here');
});
};
Any pointers? Or is there a better way.
TIA

Link function is part of directive. You can use an ng-click directive in the anchor tag in the template and provide its implementation in the linking function of the directive.
//template
Click Me
//Link function in directive
function(scope) {
scope.doThis = function() {
console.log("doing this);
}
}

Related

Syntax highlighted code snippet wont display with AngularJs ngBind

I used some Syntax highlighting API for highlighting code snippet for my web application.To do that i have used highlightjs .I created popup model and inside model i have put <pre> tag and when model open it should display my highlighted xml string.
HTML Code snippet
<pre id="tepXml" ><code class="xml">{{tepXml}}</code></pre>
In AngularJs controller dynamically bind the value to tepXml from server.
AngularJs controller
...$promise.then(function(data){
$scope.tepXml=data.xml;
}
But the problem was that when i open popup model my xml content is empty.nothing display anything.But when i removed <code class="xml"></code> from <pre> xml content would display with out highlighting.I referred some posts and used $compile in angularJs controller but the problem was still the same.
AngularJs controller with $compile
var target = angular.element($window.document.querySelector('#tepXml'));
var myHTML = data.xml;
target.append( $compile( myHTML )($scope) );
If someone knows where i went wrong please point me out.
Plunker
The quick answer is to do:
$promise.then(function(data){
$scope.tepXml=data.xml;
// Call highlight api
$timeout(function() {
$('pre#tepXml code').each(function(i, block) {
hljs.highlightBlock(block); //or whatever the correct highlightjs call is.
});
});
The more Angular way of doing things is to call a jQuery function from Angular is to write a Directive. Something like this:
.directive("highlightCode", function($interval) {
return {
restrict: "A",
scope: { highlightCode: "=" },
link: function(scope, elem, attrs) {
$scope.$watch('highlightCode', function() {
$(elem).find('code').each(function(i, block) {
hljs.highlightBlock(block); //or whatever the correct highlightjs call is.
});
}
}
});
Used like this:
<pre id="tepXml" highlight-code="tepXml"><code class="xml">{{tepXml}}</code></pre>

Angular: ng-bind-html removing ng directives from HTML data fetched from Firebase

I am saving data in firebase from WYSIWYG editor using angularJS. This data will be in HTML format.
I am fetching HTML data from firebase and with the help of angular directive ng-bind-html this HTML content is sanitized and text saved on the editor will be shown to the user. This text could contain text, images, links.
<div ng-bind-html="newHTML" ng-model="cleanText1"></div>
The HTML coming for data with link is in the below format:
<p>This is text editor link<br></p>
Now if I click this link on the page it will redirect to the URL specified.But I want this link to open the page in a div which is to the right hand side of the page.
To prevent this behavior I replaced href with ng-href using code below:
$scope.newHtml=$scope.htmlcontent1.replace("href","ng-href");
$scope.newHTML=$sce.trustAsHTML($scope.newHtml);
Doing this ng-bind-html removed ng-href
<p>This is text editor <a>link</a><br></p> Which made it unclickable.
Also I have tried to add directive for a tag so that once user clicks this link I can give my own functionality instead of redirecting the user.
Directive looks like this:
app.directive('a', function ($compile) {
return {
restrict: 'AE',
link: function (scope, elem, attrs) {
var href = elem.children('a').attr('href');
console.log("href"+href);
elem.children('a').attr('href', null);
elem.children('a').attr('ng-click', 'open()');
$compile(elem.contents())(scope);
console.log("elem"+elem.children('a').attr('href'));
scope.open = function () {
alert('1');
}
}
}
})
But directive is being called once the user clicks and is redirected to the new page.
Any ideas how to make this link open in right hand side of the page?
Appreciate your help.
Let's make some tweaks in your code to get it in action.
Try this instead.
Make your own directive for sanitizing HTML in place of using ng-bind-html.
Replace
<div ng-bind-html="newHTML" ng-model="cleanText1"></div>
To
<div cleanHtml="newHTML" ng-model="cleanText1"></div>
cleanHTML will be a customized directive.
Make below directive in app.js to render HTML content.
app.directive('cleanHTML',['$compile',function ($compile) {
return function(scope, element, attrs) {
scope.$watch(
function(scope) {
return scope.$eval(attrs.compile);
},
function(value) {
console.log(value)
// Here you can see your HTML is going to get sanitized below
element.html(value);
$compile(element.contents())(scope); // After this HTML will be sanitized.
}
)};
}])
Next is to suppress the behavior of href and apply a click function on the link so as to define your own functionality for the link.
Now replace this:
$scope.newHtml=$scope.htmlcontent1.replace("href","ng-href");
$scope.newHTML=$sce.trustAsHTML($scope.newHtml)
To
$scope.newHtml=$scope.htmlcontent1.replace
("<a ","<a ng-click=\"$event.preventDefault();open()\"");
$scope.open = function()
{
alert("Whoa! It worked :)");
//Write your code here
}
This replacement will add ng-click to Link.
For e.g. if your HTML is like this
link
It will become like this
<a ng-click="$event.preventDefault();open()" href="http://someLink">link</a>
$event.preventDefault() has been added to override href functionality so that ng-click functionality takes priority.
Now once you are able to make your link working after that comes the display part which is now a piece of cake.
You want that on click of that link content appears to the right hand side of the page.
You can fetch the content of the link and add in scope variable like this:
$scope.newHtml=$scope.htmlcontent1.replace("<a ","<a ng-click=\"$event.preventDefault();open()\"");
$scope.open = function()
{
alert("Whoa! It worked :)");
//Write your code here
//fetch the content in var content
$scope.linkContent= content;
}
use linkContent and add it to the right hand side of the DIV of HTML page where you want to display and it's done :)
<div>{{linkContent}}</div>
Hope it works.
Happy Coding !!!

how to redirect one html page to another using button click event in angularjs

i am using angularjs directive to redirect another html page.i am writing click function inside directive but i am getting page name in alert box not redirect to another html page.
sample.html:
<test1>
<button data-ng-click="click('/page.html')">Click</button>
</test1>
sample.js:
app.directive('test1',['$location', function(location) {
function compile(scope, element, attributes,$location) {
return{
post:function(scope, element, iAttrs,$location) {
scope.click=function(path)
{
alert("click"+path);
$location.path('/path');
};
}
};
}
return({
compile: compile,
restrict: 'AE',
});
}]);
i want to redirect page.html how to do this please suggest me.
Thanks.
In html,
<button ng-click="redirect()">Click</button>
In JS,
$scope.redirect = function(){
window.location = "#/page.html";
}
Hope it helps.....
Would probably make a small modification.
inject $location and use:
$scope.redirect = function(){
$location.url('/page.html');
}
The benefits of using $location over window.location can be found in the docs, but here's a summary as of (1.4.x)
https://docs.angularjs.org/guide/$location
If anyone knows how to make this redirect directly from the html in a cleaner way please let me know because I would prefer that sometimes over making a function in the controller...
I have succeeded navigation PAGE with below code in AngularJS.
$scope.click = function ()
{
window.location = "/Home/Index/";
}
In case you are using material design button 'md-button', you could do this.
I have tried giving attribute href, assigned with the link path. The redirection works well.
This could be tried if it is only redirection and there are no other tasks to be done before redirection.
<test1>
<md-button href="/page.html">Click</md-button>
</test1>

Using ng-click vs bind within link function of Angular Directive

In the link function, is there a more "Angular" way to bind a function to a click event?
Right now, I'm doing...
myApp.directive('clickme', function() {
return function(scope, element, attrs) {
scope.clickingCallback = function() {alert('clicked!')};
element.bind('click', scope.clickingCallback);
} });
Is this the Angular way of doing it or is it an ugly hack? Perhaps I shouldn't be so concerned, but I'm new to this framework and would like to know the "correct" way of doing things, especially as the framework moves forward.
You may use a controller in directive:
angular.module('app', [])
.directive('appClick', function(){
return {
restrict: 'A',
scope: true,
template: '<button ng-click="click()">Click me</button> Clicked {{clicked}} times',
controller: function($scope, $element){
$scope.clicked = 0;
$scope.click = function(){
$scope.clicked++
}
}
}
});
Demo on plunkr
More about directives in Angular guide. And very helpfull for me was videos from official Angular blog post About those directives.
I think it is fine because I've seen many people doing this way.
If you are just defining the event handler within the directive,
you do not have to define it on the scope, though.
Following would be fine.
myApp.directive('clickme', function() {
return function(scope, element, attrs) {
var clickingCallback = function() {
alert('clicked!')
};
element.bind('click', clickingCallback);
}
});
Shouldn't it simply be:
<button ng-click="clickingCallback()">Click me<button>
Why do you want to write a new directive just to map your click event to a callback on your scope ? ng-click already does that for you.
You should use the controller in the directive and ng-click in the template html, as suggested previous responses. However, if you need to do DOM manipulation upon the event(click), such as on click of the button, you want to change the color of the button or so, then use the Link function and use the element to manipulate the dom.
If all you want to do is show some value on an HTML element or any such non-dom manipulative task, then you may not need a directive, and can directly use the controller.
In this case, no need for a directive. This does the job :
<button ng-click="count = count + 1" ng-init="count=0">
Increment
</button>
<span>
count: {{count}}
</span>
Source: https://docs.angularjs.org/api/ng/directive/ngClick
myApp.directive("clickme",function(){
return function(scope,element,attrs){
element.bind("mousedown",function(){
<<call the Controller function>>
scope.loadEditfrm(attrs.edtbtn);
});
};
});
this will act as onclick events on the attribute clickme

AngularJS modal window directive

I'm trying to make a directive angularJS directive for Twitter Bootstrap Modal.
var demoApp = angular.module('demoApp', []);
demoApp.controller('DialogDemoCtrl', function AutocompleteDemoCtrl($scope) {
$scope.Langs = [
{Id:"1", Name:"ActionScript"},
{Id:"2", Name:"AppleScript"},
{Id:"3", Name:"Asp"},
{Id:"4", Name:"BASIC"},
{Id:"5", Name:"C"},
{Id:"6", Name:"C++"}
];
$scope.confirm = function (id) {
console.log(id);
var item = $scope.Langs.filter(function (item) { return item.Id == id })[0];
var index = $scope.Langs.indexOf(item);
$scope.Langs.splice(index, 1);
};
});
demoApp.directive('modal', function ($compile, $timeout) {
var modalTemplate = angular.element("<div id='{{modalId}}' class='modal' style='display:none' tabindex='-1' role='dialog' aria-labelledby='myModalLabel' aria-hidden='true'><div class='modal-header'><h3 id='myModalLabel'>{{modalHeaderText}}</h3></div><div class='modal-body'><p>{{modalBodyText}}</p></div><div class='modal-footer'><a class='{{cancelButtonClass}}' data-dismiss='modal' aria-hidden='true'>{{cancelButtonText}}</a><a ng-click='handler()' class='{{confirmButtonClas}}'>{{confirmButtonText}}</a></div></div>");
var linkTemplate = "<a href='#{{modalId}}' id= role='button' data-toggle='modal' class='btn small_link_button'>{{linkTitle}}</a>"
var linker = function (scope, element, attrs) {
scope.confirmButtonText = attrs.confirmButtonText;
scope.cancelButtonText = attrs.cancelButtonText;
scope.modalHeaderText = attrs.modalHeaderText;
scope.modalBodyText = attrs.modalBodyText;
scope.confirmButtonClass = attrs.confirmButtonClass;
scope.cancelButtonClass = attrs.cancelButtonClass;
scope.modalId = attrs.modalId;
scope.linkTitle = attrs.linkTitle;
$compile(element.contents())(scope);
var newTemplate = $compile(modalTemplate)(scope);
$(newTemplate).appendTo('body');
$("#" + scope.modalId).modal({
backdrop: false,
show: false
});
}
var controller = function ($scope) {
$scope.handler = function () {
$timeout(function () {
$("#"+ $scope.modalId).modal('hide');
$scope.confirm();
});
}
}
return {
restrict: "E",
rep1ace: true,
link: linker,
controller: controller,
template: linkTemplate
scope: {
confirm: '&'
}
};
});​
Here is JsFiddle example http://jsfiddle.net/okolobaxa/unyh4/15/
But handler() function runs as many times as directives on page. Why? What is the right way?
I've found that just using twitter bootstrap modals the way the twitter bootstrap docs say to is enough to get them working.
I am using a modal to house a user edit form on my admin page. The button I use to launch it has an ng-click attribute that passes the user ID to a function of that scope, which in turn passes that off to a service. The contents of the modal is tied to its own controller that listens for changes from the service and updates values to display on the form.
So.. the ng-click attribute is actually only passing data off, the modal is still triggered with the data-toggle and href tags. As for the content of the modal itself, that's a partial. So, I have multiple buttons on the page that all trigger the single instance of the modal that's in the markup, and depending on the button clicked, the values on the form in that modal are different.
I'll take a look at my code and see if I can pull any of it out to build a plnkr demo.
EDIT:
I've thrown together a quick plunker demo illustrating essentially what I'm using in my app: http://embed.plnkr.co/iqVl0Wb57rmKymza7AlI/preview
Bonus, it's got some tests to ensure two password fields match (or highlights them as errored), and disables the submit button if the passwords don't match, or for new users username and password fields are empty. Of course, save doesn't do anything, since it's just a demo.
Enjoy.
There is a working native implementation in AngularStrap for Bootstrap3 that leverages ngAnimate from AngularJS v1.2+
Demo : http://mgcrea.github.io/angular-strap/##modals
You may also want to checkout:
Source : https://github.com/mgcrea/angular-strap/blob/master/src/modal/modal.js
Plunkr : http://plnkr.co/edit/vFslNmBAoKPVXtdmBXgv?p=preview
Well, unless you want to reinvent this, otherwise I think there is already a solution.
Check out this from AngularUI. It runs without twitter bootstrap.
I know it might be late but i started trying to figure out why the handler got called several times as an exercise and I couldn't stop until done :P
The reason was simply that each div you created for each modal had no unique id, once I fixed that everything started working. Don't ask me as to what the exact reason for this is though, probably has something to do with the $('#' + scope.modalId).modal() call.
Just though I should post my finding if someone else is trying to figure this out :)

Resources