Display key name with spaces in ng-repeat - javascript

repeat where i am repeating key value pairs, I am having key without spaces where i need to display with space.
my ng-repeat:
ng-repeat="(key, value) in scenariosViewAll.collectionBookObject"
i am displaying in span:
<span class="accordion-title">
{{key}}
</span>
in controller i am pushing the array as :
vm.shared.collectionFlyoutObject.BusinessDrivers.push(data);
Its working fine and displaying key as BusinessDrivers.
But i need to display as Business Drivers .

You might be able to somehow work with the current key and add spaces to it the way you want. One alternative would be to just maintain state in the collection book object for the human readable form of the key. Assuming such a field keyView existed, then you would access it on the value, not the key, using this:
<span class="accordion-title">
{{value.keyView}}
</span>
Another approach would be to just maintain a map in your controller which can map the keys to the human readable forms you want, e.g.
$scope.keyViews = { };
$scope.keyViews['BusinessDrivers'] = 'Business Drivers';
And then display using this:
<span class="accordion-title">
{{keyViews[key]}}
</span>
But this approach is less nice than keeping all the relevant state in a single map, for maintenance and other reasons.

var app = angular.module('myApp', []);
app.filter('myFormat', function() {
return function(x) {
var txt = x.replace(/([A-Z]+)/g, "$1").replace(/([A-Z][a-z])/g, " $1")
return txt;
};
});
we can make a filter to create the effect.
in template
<span class="accordion-title">
{{key | myFormat}}
</span>

You can use a custom function to split camelCase. You just have to define the function in your main controller and it can be referenced anywhere in your code.
var app = angular.module('plunker', []);
app.controller('ApplicationController', function($scope) {
$scope.splitCamelCase = function(input) {
if (!input)
return;
var j = 0;
var splitString = "";
var i = 0;
for (i = 1; i < input.length; i++) {
if (input.charAt(i) == input.charAt(i).toUpperCase()) {
splitString = splitString + " " + input.slice(j, i);
j = i;
}
}
splitString = splitString + " " + input.slice(j, i);
return splitString.replace("And", "and").replace("and", " and").substr(1, splitString.length);
};
});
<!doctype html>
<html ng-app="plunker">
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
</head>
<body>
<div class="container" ng-controller="ApplicationController">
<div class="row">
{{splitCamelCase("BusinessDrivers")}}
</div>
</div>
</body>
</html>

I am copied the snippet from #Vivz to make my change
try this.
var app = angular.module('plunker', []);
app.controller('ApplicationController', function($scope) {
$scope.splitCamelCase = function(input) {
return input.replace(/([A-Z]+)/g, " $1").replace(/([A-Z][a-z])/g, " $1");
};
});
<!doctype html>
<html ng-app="plunker">
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
</head>
<body>
<div class="container" ng-controller="ApplicationController">
<div class="row">
{{splitCamelCase("BusinessDrivers")}}
</div>
</div>
</body>
</html>

If you only want to convert the key from camelCase to a space separated proper string, then I suggest you to use a filter as that would be the easiest way.
You can simply create a new filter and use that.
controller:
var myApp = angular.module('myApp',[]);
myApp.filter('splitCamelCase', function() {
return function(input) {
return input.charAt(0).toUpperCase() + input.substr(1).replace(/[A-Z]/g, ' $&');
}
});
View:
<div ng-controller="MyCtrl">
{{str | splitCamelCase }}
</div>
This is just an example. Hope this helps :) Fiddle

I think the answers above is a little bit overwhelming. It can all be narrowed down to :
.filter('splitByUppercase', function() {
return function(input) {
return input.split(/(?=[A-Z])/).join(' ')
}
})
Example
<span ng-repeat="t in test">
{{ t | splitByUppercase }}<br>
</span>
http://plnkr.co/edit/OUfmusiswNeEpSURFVRx?p=preview
If you want to lowercase the extracted words so it becomes "Business drivers" etc you can use
.filter('splitByUppercase', function() {
return function(input) {
input = input.split(/(?=[A-Z])/);
input = input.map(function(s,i) {
if (i>0) s = s[0].toLowerCase() + s.substring(1)
return s
});
return input.join(' ')
}
})

Related

Application's html loads, but js function built with angular gets stuck loading indefinitely

I'm working on an AngularJS application that reads and writes cookies and my javascript code is not working properly. My html loads fine, but when it comes to load the angular script it gets stuck loading indefinitely.
I've tried with a simple 'hello world' console log with a simple angular function and it works fine, which means the problem is not located on the angular script, but on the cookie function itself, although I can't point out where and since the page's not loading at all, I can't see any output on the console.
Here's my html code.
<!doctype html>
<html ng-app = 'cookieApp'>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-controller = 'MainController'>
<label>Save cookie:</label>
<input ng-model = 'value'>
<button ng-click = 'saveCookie(value);'>Save</button>
<h2>Get Cookie : {{getCookie()}}</h2>
<script src = 'https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.js'></script>
<script src = 'app.js'></script>
</div>
</body>
</html>
Here's the javascript code
angular.module('cookieApp', []).controller('MainController', ['$scope', 'cookie', function($scope, cookie){
$scope.value = '';
$scope.saveCookie = function(value){
cookie.write('cap_value', value);
}
$scope.getCookie = function(){
return cookie.read('cap_value');
}
}]).
factory('cookie', [function(){
return{
read: function(name){
var i, c, nameEQ = name + '=';
var ca = document.cookie.split(';');
for(i = 0; i < ca.length; i++){
c = ca[i];
while(c.charAt(0) == ''){
c = c.substring(1, c.length);
}
if(c.indexOf(nameEQ) == 0){
return c.substring(nameEQ.length, c.length);
}
}
return '';
},
write: function(name, value){
date = new Date();
date.setTime(date.getTime() + (72*4));
expires = '; expires = ' + date.toGMTString();
document.cookie = name + '=' + value + expires + '; path = /';
}
}
}]);
I expect the application to save a cookie when I type an input and then print it in the <h2> tag.
Not sure if you're aware of the ngCookies module, but it's basically the answer to your problem. It provides the $cookies service, which is the "proper" way to work with cookies, within an AngularJS application. I've combined your HTML and JavaScript into this snippet, which works exactly as I think you're expecting:
<!doctype html>
<html lang="en" ng-app='cookieApp'>
<head>
<meta charset="UTF-8">
<title>AngularJS Cookie Example</title>
</head>
<body>
<div ng-controller='MainController'>
<label>Save cookie:</label>
<input ng-model='value'>
<button ng-click='saveCookie(value);'>Save</button>
<h2>Get Cookie : {{getCookie()}}</h2>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.js'></script>
<!-- including the ngCookies module here -->
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular-cookies.js'></script>
<script>
// adding `ngCookies` to the dependencies
angular.module('cookieApp', ['ngCookies']).controller('MainController', ['$scope', '$cookies', function ($scope, $cookies) {
$scope.value = '';
$scope.saveCookie = function (value) {
$cookies.cap_value = value;
};
$scope.getCookie = function () {
return $cookies.cap_value;
};
}]);
</script>
</div>
</body>
</html>
I'll point out that the API changed in version 1.4, they added getters and setters. Just be aware of that, if you decide to upgrade your AngularJS version at some point in the future.

Angular user input calculator

I would like to do a small aplication. I did it but my if statement doesn't work. I will appreciate if somebody can tell me what is wrong.
The application presents the user with a textbox where they can list comma-separated items. If the number of items in the textbox is less than or equal to 3 (e.g., 1, 2, or 3), a message should show up under to the textbox saying "Enjoy!". If the number of items is greater than 3 (4, 5, and above), the message "Too much!". To implement this behavior, I used the split method. If the textbox is empty and the user clicks the "Check If Too Much" button, the message "Please enter data first" should show up.
Here is my code:
(function () {
'use strict';
var app = angular.module('LunchCheck', []);
app.controller('LunchCheckController', LunchCheckController);
LunchCheckController.$inject = ['$scope'];
function LunchCheckController($scope) {
$scope.name;
$scope.message;
$scope.displayNumeric = function () {
console.log($scope.name);
console.log($scope.name.length);
var lungimea = $scope.name.length;
console.log(lungimea);
if (lungimea == null) {
$scope.message = "Please enter data first";
}
else {
$scope.name = $scope.name.split(" ");
console.log($scope.name);
if ($scope.name.length = 3) {
$scope.message = "Enjoy!";
}
else {
$scope.message = "Too much!";
};
};
};
};
})();
<!doctype html>
<html ng-app="LunchCheck">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="LunchCheckController">
<form>
<input type="text" ng-model="name" placeholder="Check it!" />
<button ng-click="displayNumeric()">Check If Too Much</button>
</form>
{{message}}
</div>
</body>
</html>
From the example you gave above, I am assuming you want space-separated words, you can achieve this behavior with the below example where I have introduced a local variable to avoid updating the scope variable which is bound to the input.
(function () {
'use strict';
var app = angular.module('LunchCheck', []);
app.controller('LunchCheckController', LunchCheckController);
LunchCheckController.$inject = ['$scope'];
function LunchCheckController($scope) {
$scope.name;
$scope.message;
$scope.displayNumeric = function () {
if (!$scope.name) {
$scope.message = "Please enter data first";
}
else {
let nameSplit = $scope.name.split(" ");
if (nameSplit.length <= 3) {
$scope.message = "Enjoy!";
}
else {
$scope.message = "Too much!";
};
};
};
};
})();
<!doctype html>
<html ng-app="LunchCheck">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="LunchCheckController">
<form>
<input type="text" ng-model="name" placeholder="Check it!" />
<button ng-click="displayNumeric()">Check If Too Much</button>
</form>
{{message}}
</div>
</body>
</html>
I hope this helps.
You are missing the part where you split the comma separated items from the string. Using $scope.name.length will return only the count of characters of the input.
var lungimea = $scope.name.length;
console.log(lungimea);
if (lungimea == null)
{
$scope.message = "Please enter data first";
}
else
{
$items = $scope.name.split(",");
$scope.message = $items.length <= 3? 'Enjoy!' : 'Too much!';
};
Will give you the amount of items separated by comma.
Also try to stored the items in a different variable instead of replacing the $scope.name one (remember that you have a ng-model listening to that variable)

Angularjs: why there are 3 watchers for 1 binding?

Please take a look at the screenshot given below
As you can see in the screenshot above there are #3 watchers for a single binding.
Can anyone please elaborate why is it so?
P.S: I am using AngularJS Batarang for checking the performance.
var app = angular.module('app', []);
app.controller('appCtrl', function ($scope, $timeout) {
$scope.name = 'vikas bansal';
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-app="app" ng-controller="appCtrl">
{{name}}
</div>
</body>
</html>
I think Angular Batarang has a wrong counter of watchers. I checked with few different sources, and all except AngularJS Batarang show me single watcher on your code. Check out this question with function:
(function () {
var root = angular.element(document.getElementsByTagName('body'));
var watchers = [];
var f = function (element) {
angular.forEach(['$scope', '$isolateScope'], function (scopeProperty) {
if (element.data() && element.data().hasOwnProperty(scopeProperty)) {
angular.forEach(element.data()[scopeProperty].$$watchers, function (watcher) {
watchers.push(watcher);
});
}
});
angular.forEach(element.children(), function (childElement) {
f(angular.element(childElement));
});
};
f(root);
// Remove duplicate watchers
var watchersWithoutDuplicates = [];
angular.forEach(watchers, function(item) {
if(watchersWithoutDuplicates.indexOf(item) < 0) {
watchersWithoutDuplicates.push(item);
}
});
console.log(watchersWithoutDuplicates.length);
})();
And you can check Watchers extension for chrome. Both show 1 watcher.

Change Appended each text

I'm not getting result properly using append event instead of using ng-repeat in adding each name. Can you please help me how can I change added each name from a single input field. Tell me without using ng-repeat in this, because ng-repeat functionality is not working to me for my further running functionalities, you can solve this using jquery or javascript if it's possible without using ng-repeat. Thanks in advance..
Here is JSBin
var app = angular.module('myapp', ['ngSanitize']);
app.controller('AddCtrl', function ($scope, $compile) {
$scope.my = {name: 'untitled'};
$scope.add_Name = function (index) {
var namehtml = '<label ng-click="selectName($index)">{{my.name}} //click<br/></label>';
var name = $compile(namehtml)($scope);
angular.element(document.getElementById('add')).append(name);
};
$scope.selectName = function (index) {
$scope.showName = true;
};
});
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js"></script>
<script src="https://code.angularjs.org/1.5.0-rc.0/angular-sanitize.min.js"></script>
</head>
<body ng-controller="AddCtrl">
<button ng-click="add_Name($index)">Add Names</button>
<div id="add"></div><br/>
<form ng-show="showName">
<label>Name Change(?)</label><br/>
<input ng-model="my.name">
</form>
</body>
</html>
ng-repeat would be perfect for such cases. Not sure what makes you avoid that.
You can have a counter which will increment every time Name is added. Also pass same counter name as an argument for selectName function.
Every time selectName is called, argument value will be set as an model
Try this:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $compile) {
$scope.my = {
name: 'untitled'
};
var counter = 0;
$scope.add_Name = function(index) {
var myName = 'untitled' + counter;
var namehtml = '<label ng-click="selectName(\'' + myName + '\')">' + myName + ' //click<br/></label>';
var name = $compile(namehtml)($scope);
angular.element(document.getElementById('add')).append(name);
++counter;
};
$scope.selectName = function(val) {
$scope.my.name = val;
$scope.showName = true;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<body ng-app="plunker" ng-controller="MainCtrl">
<button ng-click="add_Name($index)">Add Names</button>
<div id="add"></div>
<br/>
<form ng-show="showName">
<label>Name Change(?)</label>
<br/>
<input ng-model="my.name">
</form>
</body>
Working demo

Replace string value with javascript object

I am currently making a small module for NodeJs. For which I need a small help.
I will tell it like this.
I have a variable with string. It contains a string html value. Now I need to replace $(title) something like this with my object { "title" : "my title" }. This can be expanded to anything with user provide. This is current code.I think that I need RegEx for do this. Can you guys help me with this?
var html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document $(title)</title>
</head>
<body>
<h1>Test file, $(text)</h1>
</body>
</html>`;
function replacer(html, replace) {
// i need a regex to replace these data
//return replacedData;
}
replacer(html, { "title" : "my title", "text" : "text is this" });
You can use a simple template function using regex,
var replacer = function(tpl, data) {
var re = /\$\(([^\)]+)?\)/g, match;
while(match = re.exec(tpl)) {
tpl = tpl.replace(match[0], data[match[1]])
re.lastIndex = 0;
}
return tpl;
}
use like
var result = replacer(html, { "title" : "my title", "text" : "text is this" });
jsfiddle
detail here
EDIT
Actually as torazaburo mentioned in the comment, it can be refactored as
var replacer = function(tpl, data) {
return tpl.replace(/\$\(([^\)]+)?\)/g, function($1, $2) { return data[$2]; });
}
jsfiddle
hope this helps
This solution uses template strings to do everything you want.
This solution has the advantage that, in contrast to the naive roll-your-own regexp-based template replacement strategy as proposed in another answer, it supports arbitrary calculations, as in
replacer("My name is ${name.toUpperCase()}", {name: "Bob"});
In this version of replacer, we use new Function to create a function which takes the object properties as parameters, and returns the template passed in evaluated as a template string. Then we invoke that function with the values of the object properties.
function replacer(template, obj) {
var keys = Object.keys(obj);
var func = Function(...keys, "return `" + template + "`;");
return func(...keys.map(k => obj[k]));
}
We define the template using ${} for substitutions (instead of $()), but escaping as \${ to prevent evaluation. (We could also just specify it as a regular string literal, but would then lose multi-line capability).
var html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document \${title}</title> <!-- escape $ -->
</head>
<body>
<h1>Test file, \${text}</h1> <!-- escape $ -->
</body>
</html>`;
Now things work exactly as you want:
replacer(html, { "title" : "my title", "text" : "text is this" });
Simple example:
> replacer("My name is ${name}", {name: "Bob"})
< "My name is Bob"
Here's an example of calculated fields:
> replacer("My name is ${name.toUpperCase()}", {name: "Bob"})
< "My name is BOB"
or even
> replacer("My name is ${last ? lastName : firstName}",
{lastName: "Jones", firstName: "Bob", last: true})
< "My name is Jones"
Since you are using ES6 template string you can use a feature called 'tagged template strings'. Using tagged template strings you are allowed to modify the output of a template string. You create tagged template string by putting a 'tag' in front of the template string, the 'tag' is a reference to a method that will receive the string parts in a list as the first argument and the interpolation values as remaining arguments. The MDN page on template strings already provides an example template string 'tag' that we can use:
function template(strings, ...keys) {
return (function(...values) {
var dict = values[values.length - 1] || {};
var result = [strings[0]];
keys.forEach(function(key, i) {
var value = Number.isInteger(key) ? values[key] : dict[key];
result.push(value, strings[i + 1]);
});
return result.join('');
});
}
You use the 'tag' by calling:
var tagged = template`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document ${'title'}</title>
</head>
<body>
<h1>Test file, ${'text'}</h1>
</body>
</html>`;
Notice that interpolation of variables uses the syntax ${'key'} instead of $(key). You can now call the produced function to get the desired result:
tagged({ "title" : "my title", "text" : "text is this" });
Run the code example on es6console
var binddingData=function(id,data){
var me=this,
arr=[];
arr=getControlBindding(id);
arr.forEach(function(node){
var content=getBinddingContent(node.getAttribute('DataTemp'),data);
binddingToHtml(node,content);
})
}
var getControlBindding=function(id){
var me=this;
return document.querySelectorAll('[DataTemp]');
}
var getBinddingContent=function(temp,data){
var me=this,
res='',
hasNull=false;
if(temp==null||typeof temp=='undefined'){
return res;
}
res= temp.replace(/\$\{([^\}]+)?\}/g, function($1, $2) {
if(data[$2]==null||typeof data[$2]=='undefined'){
hasNull=true;
}
return data[$2];
});
return hasNull?'':res;
}
var binddingToHtml=function(node,content){
var me=this;
if(node.getAttribute('IsDateTime')){
node.innerText='';//if u want change it to datetime string
return;
}
if(node.getAttribute('AddBr') && content==''){
node.innerText='';
var brTag=document.createElement('br');
node.appendChild(brTag);
return;
}
node.innerText=content;
}
You use the 'tag' by calling:
<div DataTemp="${d1}"></div>
<div DataTemp="${d2}"></div>
<div DataTemp="${d3}"></div>
<div DataTemp="${d3}+ +${d1}"></div>
<div DataTemp="${d3}/${d1}"></div>
<div DataTemp="${d4}\${d1}"></div>
<div DataTemp="(${d5}\${d1})"></div>
<div DataTemp="(${d3}\${d1})"></div>
with data var data={d1:'t1',d2:'t2',d3:'t3'}

Categories