Angularjs directive for replacing text - javascript

I am new at angularjs and I want to create a directive to change text for human readable.
scope including records coming from database. I want to change them matching humanReadable array.
angular.module('app', [])
.directive("humanReadable", function () {
return {
restrict: "A",
replace: true
}
});
var humanReadable= [{
text: "first_name",
replace: "First Name"
},
{
text: "last_name",
replace: "Last Name"
}];
function MyCtrl($scope) {
$scope.comesFromDatabase = ["first_name", "last_name"];
}
my html is like this.
<div ng-app="app">
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in comesFromDatabase">{{item}} -
<span human-readable="item"></span>
</li>
</ul>
</div>
</div>
and jsfiddle is here

As Martinspire mentioned, it's better to use a filter which might look something like below -
angular.module('myapp')
.filter('humanReadable', [function () {
return function (str) {
return str.split("_").join(" ").replace(/([^ ])([^ ]*)/gi,function(v,v1,v2){ return v1.toUpperCase()+v2; });
};
}]);
If you want directive only, with a bit of modification for the above code, it looks like this -
angular.module('myapp')
.directive('humanReadable', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.html(attrs.humanReadable.split("_").join(" ").replace(/([^ ])([^ ]*)/gi,function(v,v1,v2){ return v1.toUpperCase()+v2; }));
}
};
});
Edit: I have done it without using your humamReadable array to generalize it assuming that you might find it useful instead of using a separate array.

angular.module('app', [])
.directive("humanReadable", function () {
return {
restrict: "A",
scope: {
items: '=',
humanReadable: '='
},
link: function (scope, element, attrs) {
scope.items.forEach(function (item, i) {
if (item.text === scope.humanReadable) {
element.text(item.replace);
}
});
}
}
});
Demo: http://jsfiddle.net/vhbg6104/4/

A better way would be to use a custom filter. You can read all about it in the docs https://docs.angularjs.org/guide/filter or api https://docs.angularjs.org/api/ng/filter/filter
You could take some inspiration from the translate-filters too: https://github.com/angular-translate/angular-translate
In summary, you would probably write it like so: {{item | human-readable}} or with ng-bind like so: <span ng-bind="item | human-readable">
Use the tools and i'm sure you can figure something out

Related

Passing a string description of an Angular scope variable to a directive

I am trying to pass a dynamic variable to an angular directive. I can come up w/ a string describing the variable I am after. But I cannot bind that string to the actual Angular scope variable.
my_app.js:
(function() {
var app = angular.module("my_app");
app.controller("MyController", [ "$scope", function($scope) {
$scope.my_data = {
name: "bob",
display_detail: false,
children: [
{
name: "fred",
display_detail: false
},
{
name: "joe",
display_detail: true
}
]
}
app.directive('myDirective', ['$http', function($http) {
return {
restrict: "EAC",
link: function (scope, element, attrs) {
var model = attrs["modelToWatch"];
var watched_name = model + ".display_detail";
scope.$watch(watched_name, function (is_displayed) {
if (is_displayed) {
// do something clever w/ $http...
}
}
}
}
}]);
my_template.html:
<div ng-app="my_app">
<div ng-controller="MyController">
<my_directive model_to_watch="my_data.children[1]"/>
</div>
</div>
The idea is that the string "my_data.children[1]" gets passed to the directive. My goal is to somehow evaluate this and wind up with the actual model (the one named "joe" above).
Why not just pass it into the directive's scope?
app.directive('myDirective', ['$http', function($http) {
return {
scope: {
watchedName: '='
},
restrict: "EAC",
link: function (scope, element, attrs) {
scope.$watch(scope.watchedName.display_detail, function (is_displayed) {
if (is_displayed) {
// do something clever w/ $http...
}
}
}
}
and
<my-directive watched-name="my_data.children[1]"/>
Generally, if you have a string and want to get the scope value corresponding to it, you can use $eval on $scope to get that information. So, in your case, something like this might work:
link: function (scope, element, attrs) {
var model = attrs["modelToWatch"];
var watched_name = model.display_detail;
scope.$watch(scope.$eval(watched_name), function (is_displayed) {
if (is_displayed) {
// do something clever w/ $http...
}
}
}
You can use $scope.$parent.$watch and pass the attrs value as the first argument, i.e.
app.directive('myDirective', ['$http', function($http) {
return {
restrict: "EAC",
link: (scope, elem, attrs) => {
scope.$parent.$watch(attrs["modelToWatch"], function(newVal) {
if (newVal) {
// fancy http ajax method here
}
});
}
};
});

Angularjs binding array element ng-repeat in directive

I'm trying to display the elements of an array using ng-repeat and a directive. The directive part is important to the solution. However the element of the array is not getting bound and displays an empty value.
The fiddle can be found at http://jsfiddle.net/qrdk9sp5/
HTML
<div ng-app="app" ng-controller="testCtrl">
{{chat.words}}
<test ng-repeat="word in chat.words"></test>
</div>
JS
var app = angular.module('app', []);
app.controller("testCtrl", function($scope) {
$scope.chat = {
words: [
'Anencephalous', 'Borborygm', 'Collywobbles'
]
};
});
app.directive('test', function() {
return {
restrict: 'EA',
scope: {
word: '='
},
template: "<li>{{word}}</li>",
replace: true,
link: function(scope, elm, attrs) {}
}
});
OUTPUT
["Anencephalous","Borborygm","Collywobbles"]
•
•
•
Expected output
["Anencephalous","Borborygm","Collywobbles"]
•Anencephalous
•Borborygm
•Collywobbles
Appreciate your help
You didn't bind word.
You have used isolate scope. If you don't bind with it's scope property,it won't work.
scope: {
word: '='
},
Try like this
<test word="word" ng-repeat="word in chat.words"></test>
DEMO
var app = angular.module('dr', []);
app.controller("testCtrl", function($scope) {
$scope.chat= {words: [
'Anencephalous', 'Borborygm', 'Collywobbles'
]};
});
app.directive('test', function() {
return {
restrict: 'EA',
scope: {
word: '='
},
priority: 1001,
template: "<li>{{word}}</li>",
replace: true,
link: function(scope, elm, attrs) {
}
}
});
Your directive needs to run before ng-repeat by using a higher priority, so when ng-repeat clones the element it is able to pick your modifications.
The section "Reasons behind the compile/link separation" from the Directives user guide have an explanation on how ng-repeat works.
The current ng-repeat priority is 1000, so anything higher than this should do it.

How to pass value from custom directive to custom filter?

I have a list and want it to filter by my custom filter. But the value to it I want to put from custom directive with it's own scope. How to do it?
Body:
<body ng-controller="test">
<tr ng-repeat="item in list | myfilter: HowToPuttHereValue? >
Here is my custom filter:
.filter('myfilter', function(){
return function(array, num){
return array.slice(num, num+1);
}
})
And here is my custom directive:
.directive('mydirective', function() {
return {
restrict: "E",
template:"<input ng-model='counter'><button ng-click='getIt(counter)'>PRESS</button>",
scope:{
item: '='
},
link: function(scope, element, attr){
scope.getIt = function(counter){
console.log(counter);
}
}
}
})
Please see the Example:
JsFiddle Example
P.S. I guess I've already found a solution using "scope.$parent" . But is there a possibility to pass the value straight to a "myfilter: here? "
Here it is.
<div ng-app="hello">
<div ng-controller="forExampleController">
<ul>
<li ng-repeat="num in list | myfilter: howToPutHereFromDirective ">{{num}} </li>
</ul>
<mydirective item="list.length" filter-value="howToPutHereFromDirective"></mydirective>
</div>
</div>
function forExampleController($scope){
$scope.list = [1,2,3,4,5,6,7,8,9];
$scope.howToPutHereFromDirective = 3;
}
angular.module('hello', [])
.filter('myfilter', function(){
return function(array, num){
return array.slice(num, num+1);
}
})
.directive('mydirective', function() {
return {
restrict: "E",
template:"<input ng-model='counter'><button ng-click='getIt()'>PRESS</button>",
scope:{
item: '=',
filterValue: '='
},
link: function(scope, element, attr){
scope.getIt = function(){
scope.filterValue = parseInt(scope.counter);
}
}
}
});
Doing scope.$parent within isolated scope isn't too good indeed, because the objective of isolated scope is exactly the opposite.
I'm not sure what purpose item="list.length" two-way binding has to serve, but it is a bad idea.

Angular directive that uses dynamic value

I am trying to write a simple json pretty-printer directive in angular.js. I have:
(function(_name) {
function prettyJson() {
return {
restrict: 'E',
template: '',
link: function($scope, $element, $attr) {
console.log($element.text());
//$element.html(angular.toJson(angular.fromJson($element.text()), true));
}
};
}
angular
.module('ourApp')
.directive(_name, prettyJson);
})('prettyJson');
In my view I am doing:
<pretty-json>{{ auth.get() }}</pretty-json>
The problem is that console.log($element.text()) comes back as {{ auth.get() }} not the angular compiled result of the function call auth.get().
How do I make the directive use the result of the function call auth.get()?
I would swap to using an attribute directive and use the $attr.$observe() function to set up a $watch-like mechanism that will call a listener function every time the interpolated value of the attribute changes.
The directive code:
(function(_name) {
function _directive() {
return {
restrict: 'A',
link: function($scope, $element, $attr) {
$attr.$observe(_name, function (json) {
$element.text(angular.toJson(angular.fromJson(json), true));
});
}
};
}
angular
.module('ourApp')
.directive(_name, _directive);
})('prettyJson');
Usage in markup:
<pre pretty-json="{{ auth.get() }}"></pre>
See my Plunkr example.
You could just pass the content you want to format in as a parameter to your directive. e.g.:
JS
(function(_name) {
function prettyJson() {
return {
restrict: 'E',
scope: {
prettyJson: '='
},
template: '<pre>{{prettyJson | json}}</pre>',
};
}
angular
.module('ourApp')
.directive(_name, prettyJson);
})('prettyJson');
HTML
<pretty-json="auth.get()"></pretty-json>

AngularJS converting object to string in directive

I need some help with getting AngularJS to maintain my non-string values in directive attributes.
I was looking for a way to render a tree structure in HTML from a piece of JSON, and I found this code: http://jsfiddle.net/n8dPm/
I've been trying to adapt that for my project, as shown in the code below.
My controller/directive is shown here:
cxpControllers.controller("ProductTocCtrl", ["$scope", "$http", "$routeParams",
function ProductTocController($scope, $http, $routeParams) {
$scope.typeOf = typeOf;
//test value
$scope.contents = {
"id": 1,
"name": "Test",
subsections: [
{
id: 2,
name: "Test1.1",
link: "test11.xml",
test: 34
},
{
id: 3,
name: "Test1.2",
link: "test12.xml",
test: 95
}
]
}
}]);
cxpControllers.directive('tree', function($compile) {
return {
restrict: 'E',
scope: {key: "=", content: "="},
templateUrl: "tree_renderer.html",
compile: function(tElement, tAttr) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents);
}
compiledContents(scope, function(clone, scope) {
iElement.append(clone);
});
};
}
};
});
And then this is my template:
<script type="text/ng-template" id="tree_renderer.html">
{{key}}:
<ul ng-if="typeOf(content) == 'object' && content != null">
<li ng-repeat="(key, content) in content">
<tree key="key" content="content"></tree>
</li>
</ul>
<span ng-if="typeOf(content) != 'object'">
"{{content}}"
</span>
</script>
<ul>
<li ng-repeat="(key, content) in contents">
<tree key="key" content="content"></tree>
</li>
</ul>
This would work, except for one problem. Angular is turning the value of "content" into a string, preventing the recursion from working because it can't iterate over a string.
I have seen other questions like this, for example here, but their problem is that they used "#" in the directive scope, which converts to a string. But since I'm using "=", it should maintain the type.
Here's the output I'm seeing with the test data shown in the code above:
I would appreciate any help you can give. If you need more information I'll be happy to supply it.
The problem is with the typeOf function in your template. The compiled template doesn't find this function so it is never equal to 'object'. Add a controller to your directive to define it.
I took the plunkr and added this:
controller: function($scope) {
$scope.typeOf = function(val) {
return typeof val;
};
},
It does recognize it as an object. Check out the updated plunkr here.

Categories

Resources