Why ng-bind does not work with array? - arrays

I am wanting to create a bind to an element with an array, for when the array is changed, the HTML to be updated. But, it's not work.
HTML
<body ng-controller="Game as game">
<div>
<span ng-bind="game.testString"></span>
</div>
<div>
<span ng-bind="game.testArray"></span>
</div>
<input type="button" ng-click="game.btnAddLetter()" value="Change">
</body>
JS
angular.module('notesApp', [])
.controller('Game', [function() {
var self = this;
self.testString = 'a';
self.testArray = ['a'];
self.btnAddLetter = function() {
self.testString = 'X';
self.testArray.push('X');
}
}]);
I expected the two span would be updated, however, only the testString has been updated. For what reason did this happen? How to solve this problem?

You must use the JSON filter:
<span ng-bind="game.testArray | json"></span>

Related

How to replace text on field after click Angular?

I have HTML code with inline element:
<span class="title" ng-click="update()">Rock</span>
How to replace this element on input element after click for edit?
And then after push enter on input return back span element?
I tried with directives ng-hide(), ng-show(). But I wonder
You can use either
<span class="title" ng-hide="isEdited" ng-click="update()">Rock</span>
or
<span class="title" ng-show="!isEdited" ng-click="update()">Rock</span>
or even
<span class="title" ng-if="!isEdited" ng-click="update()">Rock</span>
In any case you will want to reference something that can be truthy. For example in your controller you would have something like this in your function
/*the init function just makes sure that everything is setup
and nothing caries over from any local storage or anything
else you may be using*/
init();
init function(){
$scope.isEdited = false;
}
$scope.update = function(){
$scope.isEdited = true;
}
What you need to do is set a variable that contains the state;
<html>
<body ng-app="app">
<div ng-controller="mainController as $ctrl">
<span ng-if="!$ctrl.isInEditMode" class="title" ng-click="$ctrl.update()" ng-bind="$ctrl.spanText"></span>
<div ng-if="$ctrl.isInEditMode">
<input type="text" placeholder="Value for rock" ng-model="$ctrl.spanText" />
<button ng-click="$ctrl.update()">Done</button>
</div>
</body>
</html>
angular.module('app', [])
.controller('mainController', function($scope) {
this.isInEditMode = false;
this.spanText = 'Rock';
this.update = (function() {
this.isInEditMode = !this.isInEditMode;
}).bind(this);
});
I have prepared a Codepen that shows an possible solution: http://codepen.io/stefferd/pen/QdQrrv

angularjs: can't dynamically set filter method with scope data

In my angular application, I came into a filter related issue. I have reproduced this issue with a simple live demo as bellow:
https://jsfiddle.net/baoqger/fpo3j6gx/2/
<div ng-app="app">
<div ng-controller="filterCtrl as f">
<input type="text" ng-model="f.inputdata"></input>
<span ng-click="f.setFilter('lowercase')">First Filter</span>
<span ng-click="f.setFilter('uppercase')">Second Filter</span>
<div ng-bind="f.inputdata | f.filtername"></div>
</div>
click First Filter or Second Filter will trigger the setFilter function.
function filterCtrl() {
this.setFilter = function ( name ){
this.filtername = name;
}.bind(this);
}
angular
.module('app', [])
.controller('filterCtrl', filterCtrl)
In the controller, the filtername will be set to lowercase or upper case, depends on which button was clicked as mentioned above.
Then set the filtername as filter method as below:
<div ng-bind="f.inputdata | f.filtername"></div>
But based on the error message, it seems that angular system can't support such usage. Any help?
Try this solution:
Javascript:
.controller('filterCtrl', ['$filter' function($filter){
var self = this;
self.setFilter = function(name){
self.filter = $filter(name);
}
}]);
HTML:
<div ng-app="app">
<div ng-controller="filterCtrl as f">
<input type="text" ng-model="f.inputdata"></input>
<span ng-click="f.setFilter('lowercase')">First Filter</span>
<span ng-click="f.setFilter('uppercase')">Second Filter</span>
<div ng-bind="f.filter?f.filter(f.inputdata):f.inputdata"></div>
</div>

Re-render NgRepeat based on user typed value input field

I have div which has some markup inside it. Basically some form fields which I want to save too on submission.
Outside this div, I have an input field where user can type an integer. Based on this integer, I would like to show or ng-repeat items.
Here's the sample code matching my problem. Kept a span inside of any form elements to focus on main issue of ng-repeat.
var app = angular.module('myapp',[]);
app.controller('ctrlParent',function($scope){
$scope.myNumber = 3;
$scope.getNumber = function(num) {
return new Array(num);
$scope.$apply();
}
$scope.$watch('myNumber', function(newVal,OldVal){
$scope.myNumber = newVal;
//alert(newVal);
})
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
<div ng-controller="ctrlParent">
<input type="text" ng-model="myNumber" ng-blur="getNumber(myNumber)"/>
<ul>
<li ng-repeat="i in getNumber(myNumber) track by $index">
<span>{{$index+1}}</span>
</li>
</ul>
</div>
</div>
here's what I tried :
Watching the variables and assigning newValue of input to scope variable does not help.
I tried using ng-blur to call the same function with updated value. Oh yes, ng-change was tried too.
Used $scope.$apply() inside getNumber function out of desperation to manually update the changes.
How do I proceed with it ? Is there any way to update the ng-repeat?
It is not an issue of ng-repeat, you have used input of type text.
Change it to number or use parseInt.
You do not need to use ng-blur, $watch, $scope.$apply() for detecting the changes in your case.
You got this part wrong: <input type="text" ng-model="myNumber">, in which you should change the input to type number.
new Array() accept number and you pass text over it.
var app = angular.module('myapp', []);
app.controller('ctrlParent', function($scope) {
$scope.myNumber = 3;
$scope.getNumber = function(num) {
return new Array(num);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
<div ng-controller="ctrlParent">
<input type="number" ng-model="myNumber" />
<ul>
<li ng-repeat="i in getNumber(myNumber) track by $index">
<span>{{$index+1}}</span>
</li>
</ul>
</div>
</div>

Using Angular model as function parameter

In this code below, i like to be able to make the length of my menu dynamic with Angular data binding by taping it in the input and getting it in real time.
<div ng-app="myApp" ng-controller="namesCtrl">
<p>Number of characters : <input type="number" ng-model="nmba" ></p>
<ul>
<li ng-repeat="x in chars track by $index">
{{ x}}
</li>
</ul>
</div>
<script>
angular.module('myApp', []).controller('namesCtrl', function($scope) {
function printCharacters(param) {
var result = [];
for (i = 1; i <= param; i++) {
result.push('a');
}
return result;
}
$scope.chars = printCharacters($scope.nmba);
});
</script>
So i wrote it as above but it is not displaying anything. Am i missing something ?
Thank you for any help.
This is becuse printCharacters called just on controller init and at this point $scope.nmba =""
You need to call this func on any change in input field.
<input type="number" ng-model="nmba" ng-change="printCharacters(nmba)">
Also you need to expose printCharacters to $scope
$scope.printCharacters = function(nbma){}

Change Behavior of controller based on calling element

I have one controller used by two different views:
<div ng-controller="MyCtrl" ng-include="slice = false">
<span ng-repeat="value in values">{{ value }}</span>
</div>
...
<span ng-controller="MyCtrl">
<div ng-repeat="value in values">{{ value }}</div>
</span>
The controller:
var MyCtrl = function($scope){
$scope.values = ['a','fancy','array'];
// if called from span
//$scope.values = ['a','fancy','array'].slice(2);
}
I'd like to know if it is possible to detect from what element the controller is being called to change the behavior of the controller.
Update: Based on #matys84pl's answer, here is my new controller
MenuCtrl = function($scope) {
$scope.slice = true;
if($scope.slice === false) { // wont go inside
$scope.data = ['a','fancy','array'];
} else {
$scope.data = ['a','fancy','array'].slice(2);
}
console.log($scope.slice); // still true for both
}
The rule is that the controller should not be aware of the view... so you should instead pass something from the view to the controller using ngInit, like this:
<div ng-controller="MyCtrl">
<span ng-repeat="value in values">{{ value }}</span>
</div>
...
<span ng-controller="MyCtrl" ng-init="isDifferent = true">
<div ng-repeat="value in values">{{ value }}</div>
</span>
and then check isDifferent value in the controller.
Update: A plunker with working example: http://plnkr.co/edit/zUgLSQcAaZX5j6JBoQAO
<div ng-controller="MyCtrl" behavior=2>...
Please forgive my lazy js - I'm used to coffeescript
var MyCtrl = function($scope, $attrs){
if $attrs.behavior != 2
$scope.values = ['a','fancy','array'];
else
$scope.values = ['a','fancy','array'].slice(2);
}
I guess you could do something similar by swapping $attrs for $element and changing your test.

Resources