Enable/disable input field depending on array length in Angular 1.5 - javascript

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

Related

Is there a way to bind input to value and track with different ng-model?

This is my problem:
I'm using ng-repeat to create input fields from an array. [a, b, c,...]
I have a button that lets you add more blank input fields.
After clicking the save button I want to be able to create a new array from the input fields.
So I'm thinking of having an iterated ng-model (item-1, item-2, item-3,...) tracking each of these inputs, then iterate through them when I hit save. But that requires me to have each input binded with a new variable that's not from [a, b, c,....].
So what I'm asking is how I can do this pseudo code with AngularJS.
<input ng-repeat="letter in letters"
set-value="letter.value"
bind-to-model="someNewVariable">
See this example:
Html :
<div class="addcontend">
<div ng-repeat="item in inputs track by $index">
<input ng-model="inputs[$index]" ng-value="item" />
<button ng-click='getVal(item)'>get input value</button>
</div>
</div>
<button ng-click="addfield()">Add field</button>
<button ng-click="log()">log</button>
Controller :
app.controller('cntr',function($scope){
$scope.inputs = ['a', 'b'];
$scope.addfield = function(){
$scope.inputs.push('')
}
$scope.getVal = function(v){
alert(v);
}
$scope.log = function() {
console.log($scope.inputs)
}
})

Array in Angular scope variable has only one member

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

Angular JS pass array of strings into directive

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

Angularjs ng-required call function

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.

How can I unbind(remove) angular models when not in DOM

Here is a simple demonstration of what I'm struggling to achieve.
<div ng-controller="MyCtrl">
<input type="button" ng-click="a=!a" value="toggle a"/>
<div ng-if="a">
<input type="text" ng-model="del.a1" />{{del}}
</div>
<input type="text" ng-model="del.a2" />
{{del}}
</div>
Initially the value of del is {} and ng-if is false the property a1 is under ng-if condition.
Test Case :
step 1 : toggle the ng-if to true so that a1 is visible
step 2 : enter some value into a1 (you can anytime enter value in property a2)
step 3 : now if i again toggle ng-if to false what I'm looking for is the property a1 is to be removed from model.(i.e i just want angular to bind those models which are visible on DOM) like this
Here is the FIDDLE for the above test case.
I guess the problem is with model used as object. but I need a solution in model as object only as I have done lot of coding based on this.
Hope I'm clear with the question.
pls Help
You can watch a value using $scope.$watch and delete a1 key from del object when a is set to false
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope) {
$scope.del = {};
$scope.a = false;
$scope.$watch('a', function(value) {
if (!value) {
delete $scope.del['a1'];
}
});
})
Please see working demo below
var myApp = angular.module('app', []);
myApp.controller('MyCtrl', function($scope) {
$scope.del = {};
$scope.a = false;
$scope.$watch('a', function(value) {
if (!value) {
delete $scope.del['a1'];
}
});
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="MyCtrl">
<input type="button" ng-click="a=!a" value="toggle a" />
<div ng-if="a">
<input type="text" ng-model="del.a1" placeholder="a1" />{{del}}</div>
<input type="text" ng-model="del.a2 " placeholder="a2" />{{del}}
</div>
In your example only the models visible in the DOM are watched.
If you mean you want the model value removed from the object then you would need to have a watch on 'a' that knows what values to remove from the model.

Categories