AngularJS - Accessing to an input array with ng-model dynamic name - javascript

I have 3 rows with 13 input fields in each row.
All the follow the rule of have a ng-model like:
First row: field[1][{1-13}]
Second row: field[2][{1-13}]
Third row: field[3][{1-13}]
So if I want to access to the first row and to the field #6 I do it like $scope.field[1][6]. The problem is that I cannot access like this to the field.
This is the HTML of the input:
<input ng-model='field[1][6]' type='text' />
I've tried to access by using: $scope.field[1][6] but it says that "field" is undefined.
Here is how I am trying to access it from my AngularJS controller:
angular.module("myModule")
.controller("myModuleController", ["$scope","$http", function($scope,$http) {
console.log($scope.field[1][2]);
}]);
This fields are created when the DOM loads and they cannot be generated with ng-repeat because some deeper factors.
I am new at AngularJS, thanks for the patience.

There should be no problem accessing that way. Maybe you have some error elsewhere.
angular.module('test', [])
.controller('Test', Test);
function Test($scope) {
$scope.fields = [
[
{name: '1-1'},
{name: '1-2'},
{name: '1-3'}
],
[
{name: '2-1'},
{name: '2-2'}
],
[
{name: '3-1'}
]
]
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<div ng-repeat='(i, lv1) in fields'>
<div ng-repeat='(j, lv2) in lv1'>
<input type='text' ng-model='lv2.name'>
<input type='text' ng-model='fields[i][j].name'>
</div>
</div>
<div>
<input type='text' ng-model='fields[1][1].name'>
</div>
</div>

Well, I found what the issue is in case someone needs to know.
Basically, in order for the array of inputs to be inside the $scope it needs to be looped with ng-repeat. So, even though you give the ng-model directive to the input it won't know about it because it wasn't processed by AngularJS.
Conclusion: You cannot just read the array of inputs this way. I worked it around by giving a dynamic ID, like field-1-6 and then using:
angular.element("#myApp").find("#field-" + firstIndex + "-" + secondIndex );
In my point of view is much better to just redo your code and make it be generated by angular. In my case it can't be done because the client doesn't want that piece of code upgraded. So, its a good workaround if you are in my situation.
;)

The code you have updated your question with unfortunately does not show
how you are initializing $scope.field
how you are using it in ng-repeat
<input ng-model='field[1][6]' type='text' /> can mean different things depending on the first two points.
Without context angular will read it like this http://jsfiddle.net/3tsw98yf/
Is that what you were looking for?

Related

Angularjs object-property

I am using this Angular Module but I can not get the work with nested data.
Here is my PLUNKR my output shows country when using object-property="country but when I try to show only states, it doesn't work.
<div class="mrg-top50">
<label>1. Autocomplete field - options list as array of objects</label>
<multiple-autocomplete ng-model="skills" object-property="country" suggestions-arr="skillsList"></multiple-autocomplete>
<label>Selected Model Value : <br />
</label>
{{skills}}
</div>
I could do it in your fiddle like this:
<multiple-autocomplete ng-model="skills" object-property="labels" suggestions-arr="skillsList[0].states"></multiple-autocomplete>
Though this is really dependent on the [0] index , which means only useful when you have just one element in the given array like in the given example.

Setting ng-model value dynamically to the value of js variable in AngularJS

Similar questions have bee asked before and I have tried solutions given to them, but my problem is little different.
Lets say I have an array of objects like this in my controller
$scope.objArray = [
{
id:1,
name:"placeholder1"
},
{
id:2,
name:"placeholder2"
}
];
now based on this array I am generating a form dynamically like this
<div ng-repeat="field in fields">
{{field.field_name}} </br>
<input type="text" ng-model="field.field_name"><br>
</div>
here in this form i want ng-model value to be set as placeholder1 and placeholder2 and not like javascript variable like field.field_name because my targets are coming from another source which contains html like below.
<p>this is sample html {{placeholder1}}. again sample html {{placeholder2}} </p>
i don't have those JS variables in here. I could not find any solution which will work this way for me so far.
here is link to plunk:
http://plnkr.co/edit/ttaq0l3PDRu4piwSluUX?p=preview
In your case it will look like this:
<div ng-repeat="field in fields">
{{field.field_name}}
<br>
<input type="text" ng-model="$parent[field.field_name]">
<br>
</div>
Note, that you have to use $parent reference because in your case you want to set property of the outer scope (where objArray is defined), however ngRepeat creates child scopes per iteration, so you need one step up.
Demo: http://plnkr.co/edit/35hEihmxTdUs6IofHJHn?p=info

Iterate through elements generated with ng-repeat in AngularJS

my app.js:
var app = angular.module('factory', []);
app.controller('Ctrl', function($scope){
$scope.users =[
{name: 'jimbo', info: ''},
{name: 'bobby', info: ''}
];
$scope.addAllInfos = function(){
};
});
my index.html:
<!DOCTYPE html>
<html ng-app="factory">
<head>
<script type="text/javascript" src="angular.min.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body ng-controller="Ctrl">
<div ng-repeat="user in users">
Name: <input value="{{user.name}}"/><br>
Tell me sth: <input/><br><br><br>
</div>
<button ng-click="addAllInfos()">add all infos</button>
</body>
When clicking on "Add all infos" i want to iterate through all my users that i have generated by using ng-repeat and save the input of every "Tell me sth" input in the info-variable of the object.
How can I do so using Angular?
Fiddle
You just need to bind every repeated input to user.info using ngModel directive:
Tell me sth: <input type="text" ng-model="user.info" />
Demo: https://jsfiddle.net/xsakgy6b/2/
Note, that in this case addAllInfos function may become redundant as two-way data binding automatically populates user objects for you.
I think what you're looking for is the ng-model attribute. You should use ng-model on your input fields as well, instead of putting the value into the value attribute. This will allow you to take full control of two-way binding in Angular.
Then you would not really need the addAllInfos function, Angular will keep track of the values and properties of each object in your repeater. The code would look like this.
<div ng-repeat="user in users">
Name: <input type="text" ng-model="user.name"/><br>
Tell me sth: <input type="text" ng-model="user.info"/><br><br><br>
</div>
Here's my updated fiddle
Your first problem is your addAllInfos() function.
You do not have your addAllInfos() function available to the view / html. You need to expose the function, either through $scope, or returned via the controller class.
You can do that like so:
$scope.addAllInfos = function() { // code here };
This will allow you to call a function from the ng-click event on your .

HTML input has both {{}} and ng-model

I have a form which contains two input fields, I want to sync the next input field when user is typing in the first input field by default, and user can edit the second field as they like, below code works fine:
<input type="text" ng-model="name">
<input type='text' value='{{name}}'>
<button ng-click='submit()'>submit</button>
However, to be able to get the value of second field, I need to put ng-model to the second field, and once I put ng-model, it won't sync anymore.
This is the example
How should I get the second field's value if I don't put a ng-model to it.
Thank you.
You can use ng-change. When user changes input 1 the ng-change method will be called and input2 will be updated .but when user change input 2 nothing will be called .
<DIV ng-app='app'>
<form ng-controller='myController'>
<input type='text' ng-model='name' ng-change="callMe()"/>
<input type='text' ng-model="name2" />{{name2}}
</form>
</DIV>
and controller js
var app = angular.module('app', []);
app.controller('myController', function($scope){
$scope.callMe =function(){
$scope.name2=$scope.name;
}
//$scope.name
//$scope.name2
})
update fiddle example
You could use the $scope.$watch Method for your needings.
I have updatet your fiddle.
What i did is easy, everytime the model changes, the $watch will be called with the new value of the model, then you just need to copy the value into the second model.
First approach that came to my mind was to ng-bind a property with a setter that would do what you want:
<input type='text' ng-model='nameModel' />
then
app.controller('myController', function($scope) {
Object.defineProperty($scope, 'nameModel', {
get: function() { return $scope.name1; },
set: function(x) { $scope.name1 = $scope.name2 = x; }
});
});
This causes any edit to nameModel to affect both name1 and name2.
Fiddle
You could do a similar wrapper around name2 to track whether it has ever been modified (dirty/pristine), and have nameModel only change scope.name2 if it is pristine.
Fiddle with better user experience
(If you're using Angular forms, it tracks the field status for you, so you could directly look at form.name2.$pristine.)
It seems that what you need is to set the value to the scope variable.
So your code would then look like this:
<input type="text" ng-model="name">
<input type='text' value="{{name}}" ng-model="somethingelse">
<button ng-click='submit()'>submit</button>
Hope that helps.

Keeping multiple controllers in scope

Is it good practice to have multiple controllers in scope so that you can go back and forth between binding to each throughout a document?
For instance, if I want to interleave the values of two sets of price/quantity/total, is it bad design to do the following: On Plnkr
<html ng-app="invoiceTest">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
<script type="text/javascript" src="invoiceTest.js"></script>
</head>
<body>
<span ng-controller="InvoiceController as invoice1">
<span ng-controller="InvoiceController as invoice2">
<div>Cost 1: <input type="number" ng-model="invoice1.cost" required ></div>
<div>Cost 2: <input type="number" ng-model="invoice2.cost" required ></div>
<div>Quantity 1: <input type="number" ng-model="invoice1.qty" required ></div>
<div> Quantity 2: <input type="number" ng-model="invoice2.qty" required ></div>
<div><b>Total 1: </b>{{invoice1.total('USD') | currency}}</div>
<div><b>Total 2: </b>{{invoice2.total('USD') | currency}}</div>
</span>
</span>
</body>
</html>
Alternatively, is there a way to carry multiple controls in scope without nesting them, or point the scope of an element to a previously declared controller instance?
Thanks for any advice. I'm just getting started with angular. I'm used to (MVVM) frameworks where the element you're binding to is instantiated in the ViewModel, not in the View itself.
I'm going to say that your use case is a little contrived. Your example really only needs one controller that had an array of objects, each one having a quantity and price.
I would say that I can't think of a situation where two controllers would be a good idea; controllers are supposed to be pretty independent, and if you have two controllers over the same code, you open yourself up to collisions and trouble. That's not to say that you shouldn't nest logic -- putting logic in directives can be a great idea, and that's kind of a controller inside a controller -- but using two controllers together usually implies that you want to share data between them, which can get clumsy fast.
Getting user to angular takes time, but in your example, I would try refactoring your controller to have an array of objects, then using directives like ng-repeat to generate your html for you, rather than writing it yourself. Angular is very powerful at turning your model into a view, and once you use it enough I think you'll see that using multiple controllers isn't the worst idea, but there's almost always a better solution that's both easier to write and easier to maintain.
EDIT:
As an example, here's your original example under one controller, and a full JSFiddle showing it working.
app.controller('OneController', function($scope){
$scope.invoices = [
{ cost: 100,
qty: 5,
total: function(){return this.cost*this.qty}
},//etc.
];
});
app.directive('compareInvoices', function(){
return {
restrict: 'E',
replace: true,
scope: {
invoices: '='
},
template:'<div>'+
'<div ng-repeat="invoice in invoices">Cost {{$index+1}}: <input type="number" ng-model="invoice.cost" required ></div>'+
'<div ng-repeat="invoice in invoices">Quantity {{$index+1}}: <input type="number" ng-model="invoice.qty" required ></div>'+
'<div ng-repeat="invoice in invoices"><b>Total {{$index+1}}: </b>{{invoice.total()}}</div>'+
'</div>'
}
});
It creates the same HTML you had originally, but could also handle any number of invoices instead of just 2, and if you wanted to compare the two invoices, you could easily do that inside your controller because it had immediate access to both.

Categories

Resources