get dynamic input value using ng-model in angularjs - angularjs

I have list of product and from each product use will add some quantity which I need in my controller.
the product list is not fix it might be 10 product (10 input box for qty) or may 100 product.
In HTML this is my code
<div class="col m3" ng-repeat="product in productlist" ng-cloak>
<h6 style="font-size:14px;">{{ product.product_name }}</h6>
<input ng-modal="qty[product.pid]" placeholder="Qty" type="number">
<button class="btn-flat" ng-click="addQty(product.pid)">ADD</button>
</div>
I am not understanding how I can get this value along with pid in controller
// ORDER ADD
$scope.addQty = function (pid) {
//$scope.qty = {};
//$scope.product = $scope.productlist;
console.log($scope.qty[pid]);
var getlistURL = $scope.baseURL+$scope.uri.uri_1+"/"+$scope.uri.uri_2+"/ng_add_to_cart/"+pid+"/";
$http.post(getlistURL).
success(function(data, status) {
if(data.length != 0) {
$scope.stockmovement = data;
$('#showStockMovement').modal('open');
}
});
};
Thanks

Here you should not try to pass just id like you did in the code. Instead of that, pass the entire object to the function and when you will manipulate its attributes, it will get effect on the page at the same time. This is how you can get real time effect of quantity change.
So modify the argument of the addQty function.
<div class="col m3" ng-repeat="product in productlist" ng-cloak>
<h6 style="font-size:14px;">{{ product.product_name }}</h6>
<input ng-modal="qty[product.pid]" placeholder="Qty" type="number">
<button class="btn-flat" ng-click="addQty(product)">ADD</button>
</div>
Then you can access any attribute of the product object in the function. Like written below:
// ORDER ADD
$scope.addQty = function (product) {
//$scope.qty = {};
//$scope.product = $scope.productlist;
console.log(product.pid);
var getlistURL = $scope.baseURL+$scope.uri.uri_1+"/"+$scope.uri.uri_2+"/ng_add_to_cart/"+product.pid+"/";
$http.post(getlistURL).
success(function(data, status) {
if(data.length != 0) {
$scope.stockmovement = data;
$('#showStockMovement').modal('open');
}
});
};
This is your solution.

Deducing from the limited information that is available, my guess is that you haven't initialized your array qty.
You should initialize your qty array to a length equal to the length of your productlist, with all initial values set to 0.
$scope.qty = [];
var initQty = function(){
for(var i = 0;i<$scope.productlist.length;i++){
$scope.qty[i]=0;
}
}();
Apart from that, your code looks fine after changing the ng-modal to ng-model, as already suggested by other folks.

I have updated my answer
angular.module('myApp', [])
.controller('myController', function($scope) {
//$scope.productlist = [];
$scope.modelData = {};
$scope.productlist = {
0:{"pid" : 1,
"product_name" : "Laptop",
},
1:{"pid" : 2,
"product_name" : "Computer",
},
2:{"pid" : 3,
"product_name" : "Camera",
},
3:{"pid" : 4,
"product_name" : "Tv",
}
}
$scope.addQty = function(pid){
alert(pid)
console.log($scope.modelData[pid])
}
});
<html ng-app="myApp">
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.js"></script>
<script type="text/javascript" src="app.js"></script>
<title>Angular-Google-Charts Example</title>
</head>
<body>
<div class="modal" style="background-color: #EDEEF1;" ng-controller="myController">
<div class="col m3" ng-repeat="product in productlist" ng-cloak>
<h6 style="font-size:14px;">{{ product.product_name }}</h6>
<input ng-model="modelData[product.pid]" placeholder="Qty" type="number">
<button class="btn-flat" ng-click="addQty(product.pid)">ADD</button>
</div>
</div>
</body>
</html>
Please check this demo. Let me know if it works!

if your productlist is of this type.
$scope.productlist =
[
{product_name: "Soap", pid: 25},
{product_name: "Bag", pid: 100}
];
Use this code
<div class="col m3" ng-repeat="product in productlist">
{{ product.product_name }}
<input ng-model="product.pid" placeholder="Qty" type="number">
<button class="btn-flat" ng-click="addQty(product)">ADD</button>
</div>
if you want to enter pid manually and get value in controller and don't want to attach with productlist
<div class="col m3" ng-repeat="product in productlist">
{{ product.product_name }}
<input ng-model="qty" placeholder="Qty" type="number">
<button class="btn-flat" ng-click="addQty(qty)">ADD</button>
</div>
and in your code type error is there change "ng-modal" to "ng-model"
seems like you want only the qty number so better try second one

https://plnkr.co/edit/gBLx1iIWL4x84ldtQAtF?p=preview
Here is a working plunker.. Changes I made are only 2 ng-model instead of ng-modal and initialised qty as object so now your quantities will be stored with pid as key of the object and qty as value of the object
for example :-
{ "1" : 6, "2" :12}
so you can basically have as many products you want with this

ng-repeat is an isolated scope , so model variables created in ng-repeat are not accessible in controller.
To solve your requirement we can follow two approaches
1.you can pass product id and quantity as two arguments and retrieve that in a function
<body ng-app="myApp" ng-controller="myCtrl">
<div class="col m3" ng-repeat="product in productlist" ng-cloak>
<h6 style="font-size:14px;">{{ product.product_name }}</h6>
<input ng-model="qty" placeholder="Qty" type="number">
<button class="btn-flat" ng-click="addQty(product.id,qty)">ADD</button>
</div>`
but this approach we dont have track of all products and all quantities, please check below plunker
https://plnkr.co/edit/zAz6FVgazOH4NWYpKb4u?p=preview
2.Second approch is following ControllerAs concepts , instead of using $scope we use ControllerAs to get values inside controller model.
<body ng-app="myApp" ng-controller="myCtrl as ctl">
<div class="col m3" ng-repeat="product in ctl.productlist" ng-cloak>
<h6 style="font-size:14px;">{{ product.product_name }}</h6>
<input ng-model="ctl.qty[product.id]" placeholder="Qty" type="number">
<button class="btn-flat" ng-click="ctl.addQty(product.id)">ADD</button>
</div>
{{ctl.qty}}
In this approach we can build an object called qty where we can keep track of all products and quantities
Please check below plunker for this approach
https://plnkr.co/edit/QIVGt8MCdPRAhHaqVA64?p=preview
Hope this meets your requirement

Related

Checking the desired checkboxes in AngularJS

I have a list of Subjects , which are used to populate
a group of checkboxes. And I have a list of SubjectIds,
where, the values of the Subjects match with a Subject Id , then
the checkbox will be checked.
For this The html code is:
<div ng-repeat="subj in Subjects">
<div ng-repeat="sub in SubjectIds">
<input type="checkbox" ng-model="subjectModel[subj.SubjectId]" ng-checked="subj.SubjectId==sub"/>{{subj.SubjectName}}
</div>
</div>
This code checks the desired checkboxes, but the checkboxes are repeated by the number of the items in SubjectIds.
You need a logic that checks if the index is in the given array. I suggest you use .indexOf() method for arrays. Here is an example:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Subjects = [
{"SubjectId":1,"SubjectName":"Name1"},
{"SubjectId":12,"SubjectName":"Name12"},
{"SubjectId":101,"SubjectName":"Name101"},
];
$scope.SubjectIds = [1, 101];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="subj in Subjects">
<input type="checkbox" ng-model="subjectModel[subj.SubjectId]"
ng-checked="SubjectIds.indexOf(subj.SubjectId)!=-1"/>
{{subj.SubjectName}}
</div>
</div>
You can use this code instead:
<div ng-repeat="subj in Subjects">
<input type="checkbox" ng-model="subjectModel[subj.SubjectId]" ng-checked="SubjectIds.indexOf(subj.SubjectId) != -1"/>{{subj.SubjectName}}
</div>

perform the ng-repeat from a position in an array

I'm trying to make an ng-repeat for a JSON of 10 elements. I would like the ng-repeat to run and display from the 5 element. how can I do it?
<div ng-repeat="item in myarray>
{{item.name}}
</div>
$scope.myarray=
[
{"name":"joe"},
{"name":"ana"},
{"name":"buf"},
{"name":"yei"},
{"name":"jsi"},//5
{"name":"sda"},
{"name":"jofrewe"},
{"name":"re"},
{"name":"we"},
{"name":"we1"}
]
the result should be:
sda
jofrewe
re
name
we1
I suggest to use ng-show to hide some elements.
const app = angular.module("demo", []);
app.controller("test", function($scope) {
$scope.myarray=
[
{"name":"joe"},
{"name":"ana"},
{"name":"buf"},
{"name":"yei"},
{"name":"jsi"},
{"name":"sda"},
{"name":"jofrewe"},
{"name":"re"},
{"name":"we"},
{"name":"we1"}
];
$scope.min = 4;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo" ng-controller="test">
<input type="range" ng-model="min"
min="0" max="10"/>
<div ng-repeat="item in myarray" ng-show="$index>=min">
{{item.name}}
</div>
</div>
You could do it manually:
ng-repeat="item in myarray.slice(4, myarray.length)"
Not necessarily clean or beautiful though.
You can provide a real expression in the ng-repeat directive. So just use slice to get the needed elements from the array:
<div ng-repeat="item in myarray.slice(5)">
{{item.name}}
</div>

ngModel checkbox not shown as selected

I'm having some trouble getting a checkbox to display the correct state (checked/unchecked) of my model. I have the following in my controller:
app.controller('PhotosCtrl', ['$scope', function($scope) {
$scope.form = {};
$scope.editPhotos = {
token: $scope.token,
idArray: $scope.idArray
};
}]);
My form looks like this:
<form accept-charset="UTF-8" name="editPhotosForm" ng-submit="submit(editPhotos);" multipart="true" novalidate>
<input name="utf8" type="hidden" value="✓">
<input name="authenticity_token" type="hidden" ng-model="editPhotos.token" ng-init="editPhotos.token='<%= form_authenticity_token %>'">
<div class="results-label"><b>{{total_count}}</b> <span ng-if="total_count == 1">Photo</span><span ng-if="total_count != 1">Photos</span> Found</div>
<div>
<div class="col">
<a ng-repeat="r in results" class="card result-link">
<div class="content result">
<div class="caption">
<input type="checkbox" ng-model="idArray[r.id]">
</div>
<div class="image-container" ng-style="{'background-image': 'url(' + r.image_url + ')'}">
</div>
</div>
</a>
</div>
</div>
</form>
On my repeater element, I call ng-init="idArray[r.id] = 'false'" to initialize a key r.id = 'false' for each item in r. I don't know if I need to do this or not. I've tried the code without it and it makes no difference. I've also tried using ng-value-true and ng-value-false but those don't seem to be working for me.
Most of the other posts I've seen on this issue deal with simple variables (e.g. $scope.someVar = true rather than more complex structures like a hash.
Here is the structure of idArray:
$scope.idArray = {1290: "false", 1291: "true", 1292: "true", 1293: "false", 1294: "false", 1414: "false"};
This is generated by the ng-init in my repeater, since the ids of the photos can't be known beforehand.
Here is what results looks like:
{
id: 1290,
company_id: null,
image_url: "http://s3.amazonaws.com/mybucket/photos/images/000/001/290/original/214.JPG?1432217895"
}
Doing the following
ng-init="idArray[r.id] = 'false'"
You're assigning the string value 'false' into your object.
Can't you deal with that inside your controller?
$scope.idArray = {};
for (var i = 0; i < $scope.results.length; ++i){
$scope.idArray[$scope.results[i].id] = (i%2 == 0);
}
And removing the ng-init="" (which is, according to Angular doc, a bad practice https://docs.angularjs.org/api/ng/directive/ngInit ).
Another thing was the anchor element that was wrapping the checkbox element. This lead to the click event that was not triggered on the checkbox, but only on the anchor.
<div class="col">
<div ng-repeat="r in results" class="card result-link">
<div class="content result">
<div class="caption">
<input type="checkbox" ng-model="idArray[r.id]">
</div>
<div class="image-container" ng-style="{'background-image': 'url(' + r.image_url + ')'}">
</div>
</div>
</div>
</div>
fiddle :
http://jsfiddle.net/patxy/wak7pwwp/

AngularJS (jsFiddle included): Scope variable not updated before sent to filter

Here's the jsFiddle: http://jsfiddle.net/VSph2/274/
I'm trying to make a filter with checkboxes.
When the user clicks the checkbox, it adds the id to an array called color_ids. I know that's working because I print the array in the console.
However, when I try to combine that with a filter, it doesn't work. I try to pass the $scope.color_ids array, but it is always passing an empty array and not passing the array with values in them.
app.controller('IndexCtrl', ['$scope', "Product", "Color", function($scope, Product, Color) {
...
// this method is triggered by a checkbox
$scope.toggleColorFilter = function(color_id) {
var index = $scope.color_ids.indexOf(color_id);
if (index > -1) {
$scope.color_ids.splice(index, 1);
} else {
$scope.color_ids.push(color_id);
}
console.log($scope.color_ids); //<-- prints the array properly with the new values.
};
}]);
and a filter that isn't working:
app.filter('productFilter', function(){
return function(input, color_ids) {
console.log(color_ids); //<-- prints an empty array all the time [ ]
return input;
}
})
This is my HTML
<h2>Products</h2>
<div class="filters col-two" ng-controller="IndexCtrl">
<h3>Color</h3>
<div ng-repeat="color in colors">
{{color.name}} <input type="checkbox" ng-model="color_ids" ng-change="toggleColorFilter(color.id)">
</div>
<h3>Shape</h3>
<h3>Material</h3>
</div>
<div class="products col-ten" ng-controller="IndexCtrl">
<div class="product" ng-repeat="product in products | productFilter:color_ids">
<h3>
{{ product.name }}
</h3>
<div class="product-thumbs">
<div class="image-wrapper" ng-repeat="product_color in product.products_colors">
<img src="{{ product_color.color.image.url }}" width="75" height="40">
</div>
</div>
</div>
</div>
I want the filter to eventually only show products with a color_id that exist in the color_ids array.
You have three divs with ng-controller="IndexCtrl" in your JSFiddle example. This is the problem. Each time the Angular compiler finds ng-controller in the HTML, a new scope is created.
<div class="filters col-two" ng-controller="IndexCtrl">
<h3>Color</h3>
<div ng-repeat="color in colors">{{color.name}}
<input type="checkbox" ng-model="color_ids" ng-change="toggleColorFilter(color.id)">
</div>
</div>
<div class="products col-ten" ng-controller="IndexCtrl">
<div class="product" ng-repeat="product in products | productFilter:color_ids">
{{ product.name }}
</div>
</div>
Simpliest way is to place this code in one controller and it will print 2 similiar arrays in your console:
<div ng-controller="IndexCtrl">
<div class="filters col-two">
<h3>Color</h3>
<div ng-repeat="color in colors">{{color.name}}
<input type="checkbox" ng-model="color_ids" ng-change="toggleColorFilter(color.id)">
</div>
</div>
<div class="products col-ten">
<div class="product" ng-repeat="product in products | productFilter:color_ids">
{{ product.name }}
</div>
</div>
</div>
JSFiddle
The filter is applied before the color_ids is updated, you should apply the filter in the controller inside the toggle function:
$filter('productFilter')($scope.products, $scope.color_ids);
Here is the working findle (at least I think): http://jsfiddle.net/VSph2/276/
Don't forget to inject the $filter in your controller.

Generate dynamic form input fields and collect field data in an array

I am stuck with this little task.
I need to generate form input fields dynamically by clicking 'add' button on the form.
The form is supposed to create DB table schema. So every input field is a DB table field name.
I am OK generating the fields dynamically but have trouble with gathering the actual data.
<form ng-controller="NewTableCtrl" ng-submit="submitTable()">
<input type='text' ng-model='table.title' placeholder='Title:'>
<input ng-repeat="field in fields" type='text' ng-model='table.fields' placeholder='Field:'>
<div>
<button type='submit'>Submit</button>
<button ng-click="addFormField()">Add</button>
</div>
</form>
.. and the controller
.controller('NewTableCtrl', function($scope) {
$scope.fields = [];
$scope.table = {};
$scope.addFormField = function () {
$scope.fields.push({});
}
$scope.submitTable = function () {
console.log($scope.table);
}
});
Looks simple. When I click 'Add' button it generates the new input field but it does it with the same model object (obveously). And that's where my misunderstanding lies. I thought that if I declare $scope.fields = [];in the controller then repeating field data will just go into the array. But it just echoes the input in every repeating input field. I understand now that this is how it is supposed to be with two way binding.
The reason I thought like this is by the analogy with an ordinary form submission where the repeating input field names become an array in the URL encoded form data.
So how do I solve this? The server needs to get an array of fields like this: fields: [field1, field2 ...] Do I need to generate input fields with different scope variable for each field? How do I do this?
Is this more complex then I thought and it needs to be a directive? If yes, please, show me how to do this.
Thanks.
Right now you are iterating $scope.fields. When you are adding a new field you push an empty object into $scope.fields, but every input's ng-model points to $scope.table.fields (which is non-existing until first input writes to it - then it will hold a string variable).
For this simple use case you could try:
app.controller('NewTableCtrl', function($scope) {
$scope.table = { fields: [] };
$scope.addFormField = function() {
$scope.table.fields.push('');
}
$scope.submitTable = function() {
console.log($scope.table);
}
});
And:
<input ng-repeat="field in table.fields track by $index" type='text' ng-model='table.fields[$index]' placeholder='Field:'>
Demo: http://plnkr.co/edit/6iZSIBa9S1G95pIMBRBu?p=preview
Take a look at this
Working Demo
html
<body>
<div ng-app=''>
<div ng-controller="questionCtrl">
<div>
<ul>
<li ng-repeat="elemnt in questionelemnt">
<div>
<div id={{elemnt.id}} style="display:inline" >
<span ng-model="elemnt.question" ng-hide="editorEnabled" ng-click="editorEnabled=true">
{{elemnt.question}}
</span>
<div ng-show="editorEnabled">
<input ng-model="elemnt.question" ng-show="editorEnabled" >
<button href="#" ng-click="editorEnabled=false">Done editing</button>
</div>
</div>
<div style="display:inline">
<span>
<input type="text" ng-model="elemnt.answer" placeholder="Answer" required/>
</span>
</div>
<span ng-hide="elemnt.length == 1">
<button ng-click="questionelemnt.splice($index, 1)">Remove</button>
</span>
</div>
<hr/>
</li>
<li>
<button ng-click="addFormField($event)">Add</button>
</li>
</ul>
</div>
<div>
<button ng-click="showitems($event)">Submit</button>
</div>
<div id="displayitems" style="visibility:hidden;">
{{questionelemnt}}
</div>
</div>
</div>
</body>
script
function questionCtrl($scope) {
var counter = 0;
$scope.questionelemnt = [{
id: counter,
question: 'Question-Click on me to edit!',
answer: ''
}];
$scope.addFormField = function ($event) {
counter++;
$scope.questionelemnt.push({
id: counter,
question: 'Question-Click on me to edit!',
answer: ''
});
$event.preventDefault();
}
$scope.showitems = function ($event) {
$('#displayitems').css('visibility', 'none');
}
}
Variation of tasseKATTs solution using a hashmap instead of an array.
This allows me to have a nice JSON object I can just for-in over in order to build my query filter.
http://plnkr.co/edit/CArP3Lkmn7T5PEPdXgNt?p=preview
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#*" data-semver="1.3.0" src="//code.angularjs.org/1.3.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<style>
div{ margin: 1em;}
input{margin-left:1em;}
</style>
</head>
<body ng-controller="myCtrl">
<h2>Using a filter map tied to ng-model to create a filter object</h2>
<div ng-repeat="field in fields">
{{field}}<input ng-model=filters[field] />
</div>
<hr>
<h3>Filter</h3>
{{filters}}
<script>
var app=angular.module("app",[]);
app.controller("myCtrl",function($scope){
$scope.filters={};
$scope.fields=["name","address","phone","state"];
});
angular.bootstrap(document,["app"]);
</script>
</body>
</html>

Resources