angularjs directive to append something to dom html value - angularjs

I want to add something to existing element's html value.
For example
<button type="button">Something</button>
I want this to be shown as
<button type="button">Something Else<button>
Code what i expect to be is something like below ,,,,
.directive('button', function (){
return {
restrict:'E',
scope: { text: 'NOT_SURE_WHAT_TO_PUT_TO_GET_DOM_HTML',
template: '{{text}} <span>Else</span>',
link: function (scope, element, attrs) {
}
};
});
Seems inside link function, element.text() gets
<span>Else</else>
So how can i get the original text value of a button and append new string to it?
------------- UPDATE --------------
All I wanted to know is how i can reuse existing text on the element in my directive.

Button is already a html element, so you can't make a directive out of it. I suggest something like my-button instead. Also, I changed restrict to 'A' as I am using the directive as an attribute. So something like this would work:
The html:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js" data-semver="1.2.17"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<button type="button" my-button xyz="'something else'">Something</button>
</body>
</html>
and the javascript:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
app.directive('myButton', function (){
return {
restrict:'A',
scope: { xyz: "#"},
template: '{{xyz}}',
link: function (scope, element, attrs) {
}
};
});
OK, on the additional information you provided, I suppose you want to use transclude within the directive. The code would then look like this (working plunker demo):
<body ng-controller="MainCtrl">
<button type="button" add="Something Else">Something</button>
</body>
and the javascript:
app.directive('button', function (){
return {
restrict:'E',
scope: { add: "#"},
template: '{{add}} <div ng-transclude></div>',
transclude: true,
link: function (scope, element, attrs) {
}
};
});

Related

Pass a server side parameter to AngularJS directive

I need to pass a variable from the server side to AngularJS.
I have the following HTML on the server side
<div ng-app="tablesApp" ng-controller="tablesCtrl" ng-init="lang='#lang';...go();" ...>
<st-date-range ?lang="#lang"? ...> </st-date-range>
...
</div>
I should put somewhere in the HTML code (actually in ng-init, but if there are other options I'm OK with that) my server side #lang value, then Angular should use that value...
I use a directive and I would like to pass the #lang(a server side ASP.NET razor variable) param to angular in order to use it in the template path:
app.directive('stDateRange', [function () {
return {
restrict: 'E',
require: '^stTable',
templateUrl: '/templates/stDateRange.en.html',
scope: false,
link: function (scope, element, attr, ctrl) {
var tableState = ctrl.tableState();
scope.$watchGroup(["minDate", "maxDate"],
function (newValues, oldValues) {
so, my server side #lang param I would like to pass to the directive in order to use it in the template URL, like this:
templateUrl: '/templates/stDateRange.#(lang).html'
P.S.:
I'll take this codepen example to show my need:
var app = angular.module('app', []);
app.directive('testDirective', function(){
var lang = 'en'; // <<< Set the variable HERE << !!!
return {
restrict: 'E',
template: '<p>my lang is "<strong>'+lang+'</strong>" </p>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="app" ng-init="lang='fr'">
<h3>Test directive for 'fr' lang</h3>
<test-directive></test-directive>
</section>
If I understand you right, you want to create dynamic templateUrl based on attr.lang.
So I would write your directive as:
app.directive('stDateRange', [function () {
return {
restrict: 'E',
require: '^stTable',
template: '<ng-include src="getTemplateUrl()"/>',
scope: false,
link: function (scope, element, attr, ctrl) {
scope.getTemplateUrl = function () {
var url = '/templates/stDateRange.' + attrs.lang + '.html'
return url;
};
var tableState = ctrl.tableState();
scope.$watchGroup(["minDate", "maxDate"],
function (newValues, oldValues) {
And HTML call:
<test-directive lang="{{lang}}"></test-directive>
Demo Plunker
[Edit 1]
If you don't want to use link, you can load constant:
app.directive('testDirective', function(Constants){
var lang = Constants.val;
return {
restrict: 'E',
template: '<p>my lang is "<strong>'+lang+'</strong>" </p>'
};
});
app.constant('Constants', {
val: 'Fess'
});
Demo Codepen
You cannot use $scope on your application directive ng-app but you can use $rootScope. I would achieve this by parsing $root.language into your directive and finally load the template dynamically. You could also access $rootScope.language inside your directive directly without parsing $root.language into it. You can do as you wish - demo punkr.
AngularJS application:
var app = angular.module('plunker', []);
app.controller('ApplicationController', function($scope) {});
app.directive('test', function ($http, $compile) {
return {
scope: {
lang: '='
},
restrict: 'E',
link: function(scope, element) {
$http.get('./template.'+ scope.lang +'.html').then(function (result) {
scope.test = 'some test';
element.html(result.data);
$compile(element.contents())(scope);
});
}
};
});
View:
<!doctype html>
<html ng-app="plunker" ng-init="language = 'en'">
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<test lang="$root.language"></test>
</div>
</div>
</body>
</html>
Template which includes your server side param:
<!doctype html>
<html ng-app="plunker" ng-init="language = '#lang'">
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<test lang="$root.language"></test>
</div>
</div>
</body>
</html>

Attach and handle ng-change from attribute directive

We have the "myCustomHandler" attribute directive:
<input type="text" my-custom-handler ng-model="myModel">
The simplified version of the directive looks like this:
.directive('myCustomHandler', function () {
return {
require: 'ngModel',
link: function (scope, elem, attrs) {
scope.change = function(){
console.log('model changed');
}
}
}});
I need a way to handle the ng-change event in the directive (trigger scope.change() function).
The reason i specifically asked for ng-change is that my input is type=text and i need to handle each key. Also, when handling the change, i need the old and new values too(so i prefer avoiding jQuery approaches).
I've already considered using $watch for the model, but it won't do it because i need to handle the event only if the model is changed by the user.
Thanks!
I hope this can help you
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.model = { name: 'World' };
$scope.name = "Felipe";
$scope.$watch('name',function(o,n){
console.log(o)
})
});
app.directive('myDirective', function($compile) {
return {
restrict: 'E',
scope: {
myDirectiveVar: '=',
//bindAttr: '='
},
template: '<div class="some">' +
'<input ng-model="myDirectiveVar"></div>',
replace: true,
//require: 'ngModel',
link: function($scope, elem, attr, ctrl) {
console.debug($scope);
//var textField = $('input', elem).attr('ng-model', 'myDirectiveVar');
// $compile(textField)($scope.$parent);
}
};
});
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<my-directive my-directive-var="name"></my-directive>{{name}}
</body>
</html>
From jquery doc:
For select boxes, checkboxes, and radio buttons, the event is fired
immediately when the user makes a selection with the mouse, but for
the other element types the event is deferred until the element loses
focus.
THis means the onChange event will fire when you click out of the input.
function listener() {
return {
link: function(scope, elem, attrs) {
elem.bind("change", function() {
alert('change');
});
}
}
}
angular.module('myApp', []);
angular
.module('myApp')
.directive('listener', listener);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<input type="text" listener>
</div>

Refresh Directive when search called

Please Check plnkr
https://plnkr.co/edit/aoGESy8pYAEIVErKr8QF?p=preview
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
<script src="app.js"></script>
<script src="search.js"></script>
</head>
<body ng-controller="MainCtrl">
<search dir-name="list-view1"></search>
<list-view1></list-view1>
<search dir-name="list-view2"></search>
<list-view2></list-view2>
</body>
</html>
angular.module('plunker', []);
function MainCtrl($scope) {
$scope.name = 'World';
}
angular.module('plunker').directive('listView1', function(){
return {
restrict: 'E',
templateUrl: 'list-view1.html',
controller: function($scope) {
$scope.items = [1,2,3,4,5];
},
replace: true,
link: function(scope, elem, attr) {
}
};
});
angular.module('plunker').directive('listView2', function(){
return {
restrict: 'E',
templateUrl: 'list-view2.html',
controller: function($scope) {
$scope.items = [6,7,8,9,10];
},
replace: true,
link: function(scope, elem, attr) {
}
};
});
we have 2 directive list-view1 and list-view2 and also we have search directive common for everywhere.
Now my requirement is when I click search of list-view1 the data of list-view1 should be update
Similarly for list-view2.
Scenario is on click of submit I have to make api call that will return me data. after receiving data I need to update list-view with new data from where call have made.
Any Idea would be great help.
If you bind items on the html elements, the view shoud be updated automatically when the items are updated. For example,
You have a function in the controller like
$scope.search = function(){
$scope.items = getNewItems();
}
and you attached this function to the search button, if you have something like that in the view
<button ng-click="search()">Search</button>
<ul>
<li ng-repeat="item in items"> {{item}} </li>
</ul>
the items in the view will be updated when you press the search button.

Watch a custom directives inner html in angular

I have a global search variable that is used by the whole app
newspaper.controller("MainController", function($scope) {
$scope.search = {query:''};
});
Then I have a contenteditable div that I want to bind to $scope.search
app.directive('search', function() {
return {
restrict: 'AE',
replace: true,
template: '<div ng-model="query" id="search"></div>',
scope: {
query: '='
},
controller: function($scope) {
// I want to watch the value of the element
$scope.$watch('query', function(newValue, oldValue){
console.log(newValue);
},true);
},
link: function(scope, element, attrs) {
// Medium JS content editable framework
new Medium({
element: element[0],
mode: Medium.inlineMode
});
}
}
});
The watch is not firing when I type new values into the div, I guess Im still confused on how to link a directive with a model. Here's the HTML
<nav ng-controller="MainControllerr">
<search context="search.query"></np-search>
</nav>
Don't think you need the watch. It's bad practise to use watch functions in your controllers anyway as it makes them really hard to test.
Here's a simplified version of what (I think) your trying to do.
DEMO
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.2/angular.js" data-semver="1.4.2"></script>
<script src="app.js"></script>
</head>
<body>
<nav ng-controller="MainController">
<pre>{{query}}</pre>
<search query="query"></search>
</nav>
</body>
</html>
app.js
var app = angular.module('plunker', []);
app.controller("MainController", function($scope) {
$scope.query = {value:''};
});
app.directive('search', function() {
return {
restrict: 'AE',
template: '<input ng-model="query.value" id="search"/>',
scope: {
query: '='
}
}
});
EDIT
If you really want to use a content editable div you'd have to try something like this:
Also, see this SO question from which I've taken and adapted code to create the demo below. Hope it helps.
DEMO2
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.2/angular.js" data-semver="1.4.2"></script>
<script src="app.js"></script>
</head>
<body>
<nav ng-controller="MainController">
<pre>{{query}}</pre>
<div search contenteditable="true" ng-model="query.value">{{ query.value }}</div>
</nav>
</body>
</html>
app.js
var app = angular.module('plunker', []);
app.controller("MainController", function($scope) {
$scope.query = {value:'rrr'};
});
app.directive('search', function() {
return {
restrict: 'AE',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
element.bind('blur', function() {
scope.$apply(function() {
ctrl.$setViewValue(element.html());
});
});
element.html(ctrl.$viewValue);
}
}
});

How to apply AngularJS Directive to an element after a nested ng-repeat is finished

The html looks like:
<div ng-controller="MainCtrl">
<outer>
<inner ng-repeat="d in data">
<div>{{d}}</div>
</inner>
</outer>
</div>
The repeat works, and the inner-directive is applied as expected.
The outer-directive looks like:
directives.directive('outer', function () {
return {
compile: function (elm) {
// ... do some jQuery
}
}
});
Without the repeat, the outer-directive is applied as expected. But with the repeat, the outer-directive is applied before the repeat writes the appropriate nodes to the DOM.
I've seen suggestions to use timeout within the directive, which seems a bit of a hack to me. Additionally it looks like there is a finished-repeat hook that I could use to then alter scope and reapply the directive.
Here is how I solved it:
HTML:
<!doctype html>
<html ng-app="myApp">
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css">
<script data-require="angular.js#1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="MainCtrl">
<outer>
<inner ng-repeat="d in data">
<div>{{d}}</div>
</inner>
</outer>
</div>
</body>
</html>
App.js:
var myApp = angular.module('myApp', ['myApp.directives']);
myApp.controller('MainCtrl', function($scope) {
$scope.data = [1, 2, 3];
});
var directives = angular.module('myApp.directives', []);
directives.directive('inner', function() {
return {
restrict: 'E',
scope: true,
link: function(scope, element, attrs) {
element.append("<div>Processing inner element.</div>");
if (scope.$last) {
element.append("Processed last inner element.");
scope.$emit('foo', "");
}
}
}
});
directives.directive('outer', function() {
return {
restrict: 'E',
scope: true,
link: function(scope, element, attrs) {
scope.$on('foo', function() {
element.append("<div>Finished outer processing.</div>");
element.append(element.getChildren());
// this is critical if jQuery altered DOM in inner directive
scope.$apply();
});
}
}
});
Output:
1
Processing inner element.
2
Processing inner element.
3
Processing inner element.
Processed last inner element.
Finished outer processing.
Plunker: http://plnkr.co/edit/tMXq7fFeNLnDbn9ORdUS
#Chandermani - Thanks for the nudge!
My suggestion is to handle the repeat inside your directive template.
directives.directive('outer-directive', function () {
return {
template:"<div ng-repeat='d in data'>"
+ "<innerDirective id={{d.id}} text={{d.text}} />"
+"</div>",
controller: function ($scope, $element, $attrs){
$scope.data = getData();
}
compile: function (elm) {
// ... do some jQuery
}
}
});

Resources