I have the following html:
<div ng-repeat="string in myStrings">
<p>{{string}}</p>
</div>
And a string like this that gets added to $scope.myStrings:
$scope.stringIwantToBeCompiled = 'I want to count to 4 via angular: {{2+2}}';
I would like the string to show 4 instead of the {{2+2}} angular expression.
Am I barking up the wrong tree here by trying to do this via $compile? If not, how is it done? Just putting it in compile fails. Do I absolutely HAVE to do this in a directive?
PLNKR FOR REFERENCE
Not sure what your exact goal is, but I can think of two approaches to accomplish this without compiling:
1) Split up the values like so:
<div ng-repeat="string in myStrings">
<p>{{string}}{{mathValue}}</p>
</div>
in controller:
$scope.mathValue = 2+2;
2) Use a function to return the string (I like using this anytime I'm doing anything binding that is non-trivial):
<div ng-repeat="string in myStrings">
<p>{{stringFunction()}}</p>
</div>
in controller:
$scope.mathValue = 2+2;
$scope.stringFunction = function() {
return 'I want to count to 4 via angular: '+$scope.mathValue;
};
I'm not 100% sure whether you are just wanting to count the number of strings in the myStrings array, or just have the ability to add a count, but given your Plunker, you could do the following:
To simply add two variables, update the following line:
$scope.stringIwantToBeCompiled = 'I want to count to 4 via angular: ' + (2+2);
If you wanted to show the count of the number of strings, swap the order of your scope variable declarations and show the myStrings length
$scope.myStrings = ['I am a string', 'I am another string', 'more strings!'];
$scope.stringIwantToBeCompiled = 'I want to count to 4 via angular: ' + $scope.myStrings.length;
Counting the strings will only give you 3, of course, because there are only 3 strings in the array.
Does that solve it for you?
UPDATE
OK - So I think what you want is the count in the string with an ng-click to correspond to the count correct?
If so, then the following on your ng-repeat would do it...
<p>{{string}} {{$index}} </p>
Using $index gives you the index of the repeating item. You can always add 1 to the $index to make it 1-based instead of zero based:
<p>{{string}} {{$index + 1}} </p>
You can append the angular expresion {{}} to the string like:
$scope.stringIwantToBeCompiled = 'I want to count to 4 via angular: ' + {{stuff or 2 + 2}};
Or use $compile Fiddle example
I really needed to use a directive with $compile like shown here:
app.directive('dynamicAlert', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamicAlert, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
http://plnkr.co/edit/bJPEyfkKsertulTN7rWp?p=preview
Related
I have the following code...
<div> {{line.tab}} </div>
This prints out the number of tabs I want (1, 2, 3) and works fine. Now I need to know how to print the tab char (\t) as many times. I would prefer not to use the controller.
In other word line.tab can be 1, 2, or 3 if it is 1 it should have 0 tabs 2 should have 1, etc.
The only way I have been able to accomplish this so far is using the controller like this (this uses 4 spaces instead of a tab but same idea)...
span(ng-repeat="i in ctrl.getNumber(line.tab) track by $index")
span {{line.n.properties.indicator}}
span {{line.n.properties.e}}
span {{line.n.properties.value}}
controller : function(){
this.getNumber = function(num) {
return new Array(num-1);
}
}
I was hoping to do this without having to use the controller function and without multiple spans.
You could try
<div ng-repeat="n in [0, 1, 2]">
	
</div>
Here's the doc for ngRepeat https://docs.angularjs.org/api/ng/directive/ngRepeat
hi i'm really struggling with this and not sure how to proceed as I haven't found anything ont his. Here's the plunkr example I'm working with: example.
I want to append something at the end of the results for example if I type S, I want to get the results and the last line should say "Look for S in other shops" :
Sauron
Bowser
Yoshi
Look for S in other shops
As you can see in my plunker, whatever I do in the template, ends up getting repeated.
Define your custom filter:
.filter('finalAppend', function(){
return function(array, value){
array.push({
name: 'Look for ' + value + ' in other shops',
type: 'good'
});
return array;
}
});
And use it like this:
<input type="text" ng-model="selected"
typeahead="datum.name for datum in (data|filter:$viewValue|limitTo:8)|finalAppend:$viewValue"
typeahead-template-url='tpl.html'>
Example
I try to do this:
<div id="{{mystring.replace(/[\s]/g, \'\')}}"></div>
but its not working. "mystring" is an object on $scope with string like "my string is this" with spaces I want to remove from the view.
Just create a dedicated filter :
angular.module('filters.stringUtils', [])
.filter('removeSpaces', [function() {
return function(string) {
if (!angular.isString(string)) {
return string;
}
return string.replace(/[\s]/g, '');
};
}])
and call it like :
<div id="{{'hi there'| removeSpaces}}"></div>
If you simply need it in one or two places it may be easier to split and join:
$scope.boundString = 'this is a string with spaces'
with that you could do in your template:
<span>my string is: {{ boundString.split(' ').join('') }}</span>
and you would get:
my string is: thisisastringwithoutspaces
another approach that has been mentioned is the regex version ('g' is for global):
<span>my string is: {{ boundString.replace(/ /g, '') }}</span>
I guess the point is that you can do whatever you want to a string within an expression. These examples are bad convention with respect to Angular dirty-checking. In Angular, bound functions (string.replace, string.split) get evaluated differently opposed to a specified value (string, boolean) when bound to a template's expression. The result of a bound function must be evaluated before Angular knows whether or not to update the DOM. This can be costly over a large app. I would suggest using another variable to track the un-spaced value:
$scope.noSpaces = $scope.boundString.replace(/ /g, '');
HTML:
<span>{{ noSpaces }}</span>
This way, when a digest loop is triggered, Angular will check if noSpaces has changed as opposed to evaluating boundString.replace(/ /g, '').
What if you are ng-repeating? Good question.
for (var idx = 0, idx < $scope.boundIterable.length, i++) {
$scope.boundIterable[i].noSpaces = $scope.boundIterable[i].boundString.replace(/ /g, '');
}
HTML:
<ul ng-repeat="iterable in boundIterable">
<li>{{ iterable.noSpaces }}</li>
</ul>
The directive mentioned works pretty well. But if you want to remove spaces for smaller texts, you can use
.split(" ").join("")
This replaces the complete spaces unlike .replace(" ","") which replaces only the first space.
You can replace all spaces by blank by using replace():
.replace(" ","")
How about {{ string.trim() }}?
Source
You can do it by using replace():
{{mystring.replace(" ","")}}
that's it I hope so.
removeSpaces() {
originalText ="hi! here i'm";
removedSpacesText = originalText.split(" ").join("");
}
I have an array with unordered keys, and I want to display them. The problem is that angular repeats it for all the keys, even when they are not set.
this is the code:
<div ng-controller="MyCtrl">
Hello, {{a[10]}}!
<p ng-repeat="b in a">
1. {{b}}
</p>
</div>
<script>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.a = [];
$scope.a[10] = "aaa";
}
</script>
and this is the output:
Hello, aaa!
1.
1.
1.
1.
1.
1.
1.
1.
1.
1.
1. aaa
i want only the array keys that are set to output. no empty b's please...
here is a jsfiddle
In essence your problem is not AngularJS related but rather how JavaScript works.
If you have an empty array and you assign an element to position 10, then JavaScript will automatically resize the array to 11 elements (since an array index starts at zero) so the index is large enough to hold your element.
You could write extra code to filter the empty elements, but based on what you write, I think you would be better off with using an object to store your data.
I have created a plnkr for your convenience: http://plnkr.co/edit/apRLuJr4zqS2zbMz322Q?p=preview
// Array
$scope.sampleArray = [];
$scope.sampleArray[10] = 'test';
// Object
$scope.sampleObject = {};
$scope.sampleObject[10] = 'test';
As you can see the syntax is very similar, but the output is completely different.
By using an object, you will automatically eliminate the empty lines.
It will also keep your code simpler since you won't have to deal with the empty array elements.
Hope that helps!
There's plenty of ways to do a cleanup on your array inside the controller (e.g. using $watchcallback on a that would remove the empty elements from it whenever it changes).
Here's a solution that uses a simple custom filter, defined in a controller:
function MyCtrl($scope) {
$scope.namea = 'Superhero';
$scope.a = [];
$scope.a[10] = "aaa";
$scope.myFilter = function(item){
return item;
}
}
<p ng-repeat="b in a | filter:myFilter">
1. {{b}}
</p>
As stated in filter docs, the 'filter' filter can take a function:
function: A predicate function can be used to write arbitrary filters.
The function is called for each element of array. The final result is
an array of those elements that the predicate returned true for.
I have spent the better part of a few hours writing and re-writing this, and am probably just going to write my own directive here if there isn't an answer.
I have a columnized display of inputs, 10 in each of the 6 columns. I am using 2 ngRepeat directives to display them. I am placing 6 fiddles below with my varied attempts at getting them to work right. The problem is, when I use an array of objects, all the data are updated simultaneously. View Fiddle #1 below to see the example.
Here is a quick snippet of the code, which you can also see on the fiddle page. If anyone has some pointers or a way to get #1, #2, or #6 to work, please let me know!
HTML:
<div ng-controller='EntryCtrl'>
<div class="span2" ng-repeat="a in [0,1,2,3,4,5]">
<div ng-repeat="i in entry.slice($index*10, ($index*10)+10)" ng-class="{'control-group': true, error: !entry[($parent.$index*10)+$index].correct}">{{($parent.$index*10)+$index}}<input type="text" class="span12" id="entry-{{($parent.$index*10)+$index}}" ng-model="entry[($parent.$index*10)+$index].input" /></div>
</div>
</div>
Javascript:
var myApp = angular.module('myApp', []);
myApp.controller('EntryCtrl', ['$scope', function($scope) {
$scope.entry=filledArray(60,{input:'',correct:true});
}]);
function filledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
Fiddle #1: Array of objects using ng-model pointing to entry using $index and $parent.$index: http://jsfiddle.net/DFEkG/ -- All models update simultaneously
Fiddle #2: Array of objects using ng-model pointing to i instead of $index: http://jsfiddle.net/DFEkG/1/ -- All models update simultaneously
Fiddle #3: Array using ng-model pointing to entry using $index and $parent.$index: http://jsfiddle.net/DFEkG/2/ -- Weird behavior
Fiddle #4 Array using ng-model pointed to i instead of $index: http://jsfiddle.net/DFEkG/3/ -- Broken
Fiddle #5 Array using only $index and $parent.$index and array only in ng-repeat directive: http://jsfiddle.net/DFEkG/4/ -- WORKS! But not as object
Fiddle #6 Same as technique as 5, but with an object: http://jsfiddle.net/DFEkG/5/ -- Same as fiddles 1 and 2
The problem is in your filledArray function. It assigns the same exact object to each array item. The same object {input: '', correct: true} is referenced in all 60 instances.
So, to fix it you can simply make a new copy of it on each iteration:
function filledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = angular.copy(val);
}
return rv;
}
Fiddle.