I am a beginner to AngularJS and thanks to the Angular community on Stackoverflow which is willing to help a newbie like me, I am learning it very well thanks a lot for that.
Today I would like to add a feature to the exercise I was doing yesterday (which can be found here). I would like to keep a record of the pairs of numbers that the user has typed in and show it as a list of lines. To do that, I introduce an array of number objects. Pressing the button adds the current pair to the array.
Currently, it seems like the array contains only member whatever I do to push new members to it. Can anyone help me find my mistake?
var saApp = angular.module("saApp", []);
saApp.controller('numberController', function($scope) {
$scope.numbers = [];
$scope.number = {
number1: 0,
number2: 0,
sumIt: function() {
var numberObject;
numberObject = $scope.number;
return parseInt(numberObject.number1) + parseInt(numberObject.number2);
}
};
$scope.pushIt = function() {
if ($scope.number !== undefined)
$scope.numbers.push($scope.number);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="saApp" ng-controller="numberController">
<input type="text" ng-model="number.number1" placeholder="Enter a number here">
<input type="text" ng-model="number.number2" placeholder="Enter another number here">
<br />{{number.number1}} + {{number.number2}} = {{number.sumIt()}}
<br />
<br />
<button ng-click="pushIt()">Push</button>
<div ng-repeat="number in numbers">
{{number.number1}} + {{number.number2}} = {{number.sumIt()}}
<br />
</div>
</div>
One change in your current code just clone the $scope.number before pushing into the $scope.numbers array.
$scope. pushIt = function() {
if ($scope.number !== undefined)
$scope.numbers.push(angular.copy($scope.number));
}
Why we should clone before pushing.
The $scope.number object is the same always thus all of the elements in the array will have the same $$hashkey and you will get this error
So you should clone or copy the object before pushing, so that the array has new element objects in it.
Working code here
Use object having keys as input fields to be pushed in ng-repeat. Every repeated object will have his own scope and will update biding values accordingly.
Try this:
var saApp = angular.module("saApp", []);
saApp.controller('numberController', function($scope) {
$scope.numbers = [];
$scope.pushIt = function() {
var obj = {
number1: 0,
number2: 0,
sumIt: function() {
return parseInt(this.number1) + parseInt(this.number2);
}
}
$scope.numbers.push(obj);
}
$scope.pushIt();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="saApp" ng-controller="numberController">
<button ng-click="pushIt()">Push</button>
<div ng-repeat="number in numbers">
<input type="text" ng-model="number.number1" placeholder="Enter a number here">
<input type="text" ng-model="number.number2" placeholder="Enter another number here">{{number.number1}} + {{number.number2}} = {{number.sumIt()}}
<br />
</div>
</div>
Fiddle here
$scope.pushIt = function() {
if ($scope.number)
$scope.numbers.push($scope.number);
}
Replace your pushIt function by this Code
Related
Im new to Angular 1.5. I want have an array and when it is empty, I want to disable an input field. When it's not empty, I want to enable the field. But it's not working as expected. I've put together a simple jsfiddle.
angular.module('demoApp', [])
.controller('MainController', MainController);
function MainController() {
var vm = this;
this.data = ['a', 'b'];
setInterval(function() {
if (vm.data.length === 0) {
vm.data = ['a', 'b'];
} else {
vm.data = [];
}
console.log('vm.data is now ', vm.data);
}, 2000);
}
And
<div ng-app="demoApp" ng-controller="MainController as mainCtrl">
<input type="text" ng-disabled="!data" />
<br />
data is {{ data }}
</div>
I would expect each time the setInterval() method is executed, the HTML would be updated, so the input would cycle between enabled and disabled. But doesn't work and the template isn't outputting the data array.
Since you are using controller instance you need to use its alias mainCtrl, To check if data is empty or not check its length property.
<div ng-app="demoApp" ng-controller="MainController as mainCtrl">
<input type="text" ng-disabled="mainCtrl.data.length == 0" />
<br />
data is {{ mainCtrl.data }}
</div>
Also, You should use $interval instead of setInterval.
Fiddle
I have the below directive, which outputs the number and the corresponding string value from the array data.
var app = angular.module("test",[]);
app.controller("Ctrl1",function($scope){
$scope.range = 5;
$scope.data = ['a','b','c','d','e',];
});
app.directive("myDirective", function(){
return {
restrict: "EA",
scope: true,
template: "<div ng-repeat='n in [] | range:range'>{{n + 1}} - {{data[n]}}</div>"
};
})
.filter('range', function() {
return function(input, total) {
total = parseInt(total);
for (var i=0; i<total; i++)
input.push(i);
return input;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="Ctrl1">
<label>Edit range </label> <input ng-model="range" /><br>
<label>edit data </label> <input ng-model="data" /><br>
<my-directive></my-directive>
</div>
</div>
This runs as expected on load however when the user edits the ng-model="data" the output breaks as it is including the , as an item in the array.
What is the best way to get this working so that when the user updates the data the directive still treat the array like it did initially? (I am happy to either comma seprate items in data or another method such as | if required.)
The better way would be to have a function to push and pop the input data in the array. Something like the following :
HTML :
<input type="text" ng-model="inputdata" ng-click="pushDataInArray(inputdata);"></input>
//And similarly have a function to pop the data from whichever index from the array.
JS:
$scope.pushDataInArray = function(inputdata){
$scope.data.push(inputdata);
};
This would be a better approach IMO.
<input ng-model="data" /> will write the new value into a string an not an array. you need to split the string into an array See http://www.w3schools.com/jsref/jsref_split.asp
I have a form where I'm taking a input and according to that creating a number of input boxes. The javascript code is given below for that.
for(i = 1; i <= c; i++) { //c = total input count
block = block + '<div class="row">'+
'<div class="form-group col-lg-12">'+
'<input id="name" ng-model="new.var'+i+'name" type="text" class="form-control">'+
'<input id="type" ng-model="new.var'+i+'type" type="text" class="form-control">'+
'</div>'+
'</div>';
}
document.getElementById("vars").innerHTML = block;
Above code is working fine & ng-model are getting generated dynamically fine, like new.var1name , new.var1type , new.var2name , new.var2type and so on.
But how to get those variables in my controller?
If I generate those variables in my controller like below then its giving error that it cant find 'name'.
var var1 = [];
for(i = 1; i <= c; i++) { //c = total input count
var item = {};
console.log('var'+i+'name', 'var'+i+'unit');
item['name'] = $scope.new.var+i+name;
item['type'] = $scope.new.var+i+type;
var1.push(item);
}
console.log(JSON.stringify(var1));
so I have used like below but now no error is there but the var1 is empty.
var var1 = [];
for(i = 1; i <= c; i++) {
var item = {};
console.log('var'+i+'name', 'var'+i+'type');
item['name'] = $scope.new['var'+i+'name'];
item['type'] = $scope.new['var'+i+'type'];
var1.push(item);
}
console.log(JSON.stringify(var1));
Please anyone help me to find what I'm doing wrong or is it possible to do???
I would suggest that, rather than generate the html in your controller, you write this html in your view, and repeat it using angular's ng-repeat directive: https://docs.angularjs.org/api/ng/directive/ngRepeat. Something like this (not tested):
<div ng-repeat="item in c track by $index">
<input id="name" ng-model="name[$index]" type="text" class="form-control">
<input id="type" ng-model="type[$index]" type="text" class="form-control">
</div>
You should then be able to access the name and type arrays from $scope within your controller. If 'c' is the ng-model for your original input (which defines the number of times to repeat) then new fields should get added dynamically if this the desired functionality?
EDITED
in your controller
$scope.c = 5;
$scope.getNumber = function(num) {
return new Array(num);
}
in your view
<div ng-repeat="i in getNumber(c) track by $index">
<input id="name" ng-model="name[$index]" type="text" class="form-control">
<input id="type" ng-model="type[$index]" type="text" class="form-control">
</div>
use $scope['new.var'+i+'name']
there are two ways accessing object property in JavaScript:
if you know the name, you can do $scope.new.var1name
if the name is dynamic, which is your case, you can use the bracket syntax $scope['new.var'+i+'name']
It is possible make the required value dependet of some funcion?
Something like this? I want to do this because I want to change the required attribute to some form inputs...
HTML:
Name: <input type="text" ng-model="user.name" ng-required="isRequired('name')" />
Age: <input type="text" ng-model="user.age" ng-required="isRequired('age')" />
JS:
$scope.isRequired(fieldName){
$scope.requiredFields = [];
//$scope.requiredFields = STUFF FROM SOME REST SERVICE
for (i in requiredFields) {
if (requiredFields[i] == fieldName){
return true;
}
}
return false;
}
Updated Answer:
So based on your updated OP, what you want is certainly doable. The problem with what you were trying to do is that ng-required has no ability to execute a function, it only reads a boolean. But we can dynamically create variables based on data from the server to automatically set fields to required:
Updated Plunker
<form>
Name: <input type="text" ng-model="user.test" ng-required="name" /><br/>
<input type="text" ng-model="user.name" ng-required="age" />
<br/>
<button type="submit">Submit</button>
</form>
Note that I put a $scope property for each input in the ng-required attribute. Now we can dynamically create that $scope property and set it to true if our data says we need to:
$scope.isRequired = function(){
$scope.requiredFields = [];
$http.get('fields.json')
.success(function(data){
$scope.requiredFields = angular.fromJson(data);
console.log($scope.requiredFields.required)
for (i = 0; i < $scope.requiredFields.required.length; i++) {
$scope[$scope.requiredFields.required[i]] = true
}
console.log($scope[$scope.requiredFields.required[0]]);
})
//$scope.requiredFields = STUFF FROM SOME REST SERVICE
}
$scope.isRequired()
So it is iterating over an array of required fields received from the server, and then dynamically creating a $scope property for each one that is required, and setting it to true. Any field that has that $scope property in it's ng-required will be required now. Anything not dynamically created will just return false, and ng-required doesn't trigger.
Original answer:
Plunker
As Pratik mentioned, ng-required only accepts a Boolean value, but we can toggle the value of that with a function.
HTML
<form>
Name: <input type="text" ng-model="user.name" ng-required="isRequired" />
<br/><button ng-click="toggle()">Required: {{isRequired}}</button>
<button type="submit">Submit</button>
</form>
code:
$scope.isRequired = true;
$scope.toggle = function() {
$scope.isRequired = !$scope.isRequired;
}
I know this is a couple of years old and so AngularJS may have changed, but the accepted answer as it stands today isn't correct. You can very easily execute a function within ng-required, as it takes an expression, which can be a function. For example:
index.html
<div ng-controller="ExampleController" class="expressions">
Expression:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
<ul>
<li ng-repeat="expr in exprs track by $index">
[ X ]
<code>{{expr}}</code> => <span ng-bind="$parent.$eval(expr)"></span>
</li>
</ul>
</div>
script.js
angular.module('expressionExample', [])
.controller('ExampleController', ['$scope', function($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}]);
In script.js, a function addExp is defined and added to the scope, and then it's called in the ng-click directive of the a tag, which also takes an expression as its argument.
This code is taken directly from the AngularJS documentation on expressions. It doesn't use ng-require directly, but any directive that takes an expression will work the same. I have used the same syntax to use a function for ng-require.
I need to elaborate some functions in a ng-repeat, but i can't access the right field with the $watch function.
This is my code but prolly I access the field in a wrong way that cause me Javascript error of undefined.
.html
<body ng-controller="MainCtrl">
<div ng-form="mainForm">
<a ng-click="addNewr1()">Add New r1</a>
<ul>
<li ng-repeat="rb_r1 in currForm.r1" ng-form="subFormr1">
<input type="number" step="0.1" ng-model="rb_r1.runo" name="r_runo" required />
<input type="number" step="0.1" ng-model="rb_r1.rdue" name="r_rdue" required />
<input type="number" step="0.1" ng-model="rb_r1.rsomma"/>
</li>
</ul>
</div>
</body>
.js
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function ($scope) {
$scope.master = {};
$scope.currForm.r1 = [];
$scope.addNewr1 = function (){
$scope.currForm.r1.push({ runo: 0,rdue: 0,rsomma: 0 });};
$scope.$watch('rb_r1.runo + rb_r1.rdue', function (value) {
$scope.rb_r1.rsomma= value;
}, true);
});
So I found a fiddle and modifying it I get the solution, but in a limited way, cause I had to access to the field in a static way. How can i do that in a dinamic way?
http://jsfiddle.net/fe9ws/
TY All!
I am still not clear on what you attempted to do but you do not need a $watch for the task described:
Since "somma" is a calculated You can define your field like this and it will produce the desire result:
<input type="number" name="somma" value="{{social.uno + social.due}}">
I resolved with a for in the $watch function..
$scope.$watch('formData.socials',
function(value){
var i;
for(i = 0; i < value.length; i++)
value[i].somma = value[i].uno + value[i].due;
}, true);
see the fiddle! Ty all
http://jsfiddle.net/JWTE2/