I am trying to create js array with key = trener_id and values = selected service ID from the checked checkboxes
Whatever I do the array is being created but also there are many empty values that are being saved in the array. How to avoid this and finally to have a clean JS array with key trener_id and values only selected services IDs
Also is it possible and how to add sub-array that has Price customer and Price trener attached to each selected service value?
The php equivalent of the desired array format would be:
$trener_services = array(1){
[13]=>
array(2) {
[47]=>array(2){
['Price_customer']=>
string(5) "10.00",
['Price_trener']=>
string(4) "5.00"
}
[45]=>array(2){
['Price_customer']=>
string(5) "60.00",
['Price_trener']=>
string(5) "10.00"
}
}
}
Hope the question is clear..
Thanks for your time
var trener_services;
$('body').on('change', '.service_check', function() {
trener_services = new Array();
$('.service_check:checked').each(function(){
var sid = $(this).val();
var trener_id = $(this).attr('data-trener');
if(!trener_services[trener_id]){
trener_services[trener_id] = [];
}
trener_services[trener_id].push($(this).val());
console.log(trener_services);
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<table class="table table-hover table-striped text-left trener_service_table tren_ser_13">
<thead>
<tr>
<th class="text-left success">Select</th>
<th class="text-left success mw20">Service type</th>
<th class="text-left success">Price customer</th>
<th class="text-left success">Price trener</th>
</tr>
</thead>
<tbody><tr class="tren_ser_row_47">
<td><input id="service_check_47" data-trener="13" type="checkbox" class="service_check" value="47"></td>
<td><label for="service_check_47">Single play</label></td>
<td><input data-id="47" id="trener_client_price_47" class="short client_price client_price_47" type="text" value="10.00"></td>
<td><input data-id="47" id="trener_bonus_price_47" class="short bonus_price_47" type="text" value="5.00"></td>
</tr>
<tr class="tren_ser_row_45">
<td><input id="service_check_45" data-trener="13" type="checkbox" class="service_check" value="45"></td>
<td><label for="service_check_45">Double play</label></td>
<td><input data-id="45" id="trener_client_price_45" class="short client_price client_price_45" type="text" value="60.00"></td>
<td><input data-id="45" id="trener_bonus_price_45" class="short bonus_price_45" type="text" value="10.00"></td>
</tr>
<tr class="tren_ser_row_46">
<td><input id="service_check_46" data-trener="13" type="checkbox" class="service_check" value="46"></td>
<td><label for="service_check_46">Triple play</label></td>
<td><input data-id="46" id="trener_client_price_46" class="short client_price client_price_46" type="text" value="50.00"></td>
<td><input data-id="46" id="trener_bonus_price_46" class="short bonus_price_46" type="text" value="10.00"></td>
</tr>
</tbody>
</table>
As one commenter suggested, you must use an Object instead of an Array. (Your trener_id is a string, not a number, unless JQuery automatically converts strings to numbers; I don't use JQuery so I wouldn't know.)
//this is a global variable so you can use it elsewhere
let trener_services;
document.body.addEventListener( "change", () => {
trener_services = Object.fromEntries(
//get all the checked services:
[ ...document.querySelectorAll('.service_check:checked') ].
//map them to object entries of the form [ key, value ]
map( checkboxElement => [
//key: the data-trener attribute
//checkboxElement.getAttribute( "data-trener" ),
//key: the checkbox's value field
checkboxElement.value,
//value: an array of the checkbox's value as well as the two sibling values you wanted
[
checkboxElement.value,
document.querySelector( "#trener_client_price_" + checkboxElement.value ).value,
document.querySelector( "#trener_bonus_price_" + checkboxElement.value ).value
]
] )
);
console.log( trener_services );
})
Here is the same function, without the sub-array you requested. (Your question was very unclear, but I am trying my best.)
//this is a global variable so you can use it elsewhere
let trener_services;
document.body.addEventListener( "change", () => {
trener_services = Object.fromEntries(
//get all the checked services:
[ ...document.querySelectorAll('.service_check:checked') ].
//map them to object entries of the form [ key, value ]
map( checkboxElement => [
//key: the data-trener attribute
//checkboxElement.getAttribute( "data-trener" ),
//key: the checkbox's value field
checkboxElement.value,
//value: only the checkbox's value
checkboxElement.value
] )
);
console.log( trener_services );
})
Related
I am a beginner at Javascript and I have a problem with my Javascript form objects. How do I loop through the entire form object select only the elements that are checked by the user. So far I have tried the following:
//Gets the selected checkbox values:
function getCbValues() {
var chkMouse = document.getElementById("chkMouse");
var chkKeyboard = document.getElementById("chkKeyboard");
var chkDVD = document.getElementById("chkDVD");
var chkSound = document.getElementById("chkSound");
var myFormElem = myForm.elements;
for (var i = 0; i < myFormElem.length; i++) {
if (myFormElem[i].type == "checkbox") {
if (myFormElem.checked == true) {
if (myFormElem[i].elementId == chkMouse) {
alert("This is the Mouse");
}
if (myFormElem[i].elementId == chkKeyboard) {
alert("This is the Keyboard");
}
if (myFormElem[i].elementId == chkDVD) {
alert("This is the DVD");
}
if (myFormElem[i].elementId == chkSound) {
alert("This is the Sound");
}
} else {
alert("Nothing");
}
}
}
}
I have declared all the var for all the different checkbox Id's. Here is the html:
<form action="" name="form1">
<!--Checkbox table-->
<table>
<!--Select Add on Item's-->
<tr class="firstHeader">
<th colspan="3">
<h3>Select Add On Items (Optional):</h3>
</th>
</tr>
<tr>
<th colspan="2">Add On Items</th>
</tr>
<tr>
<td><label>Mouse</label>
<td><input type="checkbox" name="chkMouse" value="Mouse" id="chkMouse" price="31" /></td>
</tr>
<tr>
<td><label>Keyboard</label></td>
<td><input type="checkbox" name="chkKeyboard" value="Keyboard" id="chkKeyboard" price="42" /></td>
</tr>
<tr>
<td><label>DVD Rome Drive</label></td>
<td><input type="checkbox" name="chkDVD" value="DVD Rome Drive" id="chkDVD" price="56" /></td>
</tr>
<tr>
<td><label>Sound Card</label></td>
<td><input type="checkbox" name="chkSound" value="Sound Card" id="chkSound" price="83" /></td>
</tr>
</table>
As you can see I have put the form into a table. But my issue is that whenever I run the Javascript the returned value is always null or undefined. My question is that how can I make a form object in Javascript loop over all these elements and in the end only return the values of the checkboxes that are checked. Can someone help me with this issue please. Thanks in advance !!
The reason you get nothing returned is because your getCbValues() function is not getting called anywhere in the code you have shown. Even if it was it would only show the current state as you haven't set up anything to respond to changes.
What I would do is set up event listeners to detect when a checkbox is checked and then do something with that information. You should do that outside of any function.
You can set an event listener like this:
var chkMouse = document.getElementById("chkMouse");
chkMouse.addEventListener('change', () => {
alert('this is the mouse')
})
Assuming you want to submit your form with the checked data you would probably add the item to an array that is then submitted as form data on submit.
Additionally you would want to check whether someone un-checks your item. You could do that like this:
chkMouse.addEventListener('change', () => {
if (chkMouse.checked) {
alert('mouse added')
} else {
alert('mouse removed')
}
})
Il jump right to the case.
Basicly when you have an array of objects like this:
{id: 1, name: "Hello", location: "New york", streetNumber: 50}
Then you have an input field:
<input type="text" ng-model="search.$" />
And the following table:
<table>
<thead>
<th>Name</th>
<th>Location</th>
<th>Street number</th>
</thead>
<tr ng-repeat="item in items | filter:search">
<td>
{{item.name}}
</td>
<td>
{{item.location}}
</td>
<td>
{{item.streetNumber}}
</td>
</tr>
</table>
So when you type into the search field: "1".
Then you will also get the object where the id matches 1.
My question is how can i exclude items that are not shown?
Fiddle
Well, take a look at the docs
A special property name ($ by default) can be used (e.g. as in {$:
"text"}) to accept a match against any property of the object or its
nested object properties.
That's why the results with ids satisfying the criterion get included.
Solution 1, simple but slower working
Add another filtering
<tr ng-repeat="item in items | filter : search | filter : { id: '!search.$' }">
Solution 2, difficult but quick
Consider writing your own filter, e.g.
JS
app.filter('searchFields', function () {
return function (array, fields, string) {
fields = fields.split(',');
var i,
fieldsLength = fields.length;
return array.filter(function (item) {
for (i = 0; i < fieldsLength; i++) {
if (typeof item[fields[i]] === 'undefined') {
continue;
}
return (item[fields[i]] + '').indexOf(string) !== -1;
}
});
};
});
HTML
<tr ng-repeat="item in items | searchFields : 'name,location,streetNumber' : search.$">
I want to sum the product count which are added dynamically using JSON array.
<tr ng-repeat="(key,val) in form.products">
<td>{{ProductName(key)}}</td>
<td >
<input type="text" name="products" ng-model="form.products[key]" class="form-control">
</td>
</tr>
How can I get the sum of products in the above example?
use lodash
presuming the value you want to sum is in a property called 'price':
{{_(form.products).mapValues('price').sum()}}
you may need to get lodash into your scope first. In the controller, something like:
scope._ = _;
or this approach
you are using an 'object with properties' instead of 'an array of objects', that is why you cant use your example above , $scope.products.length;....
Your product object with its properties :
$scope.products ={
"1":"20",//property 1 with value 20
"2":"35",//property 2 with value 35
"3":"150"//property 3 with value 150
}
The data Object (object with properties as you have it):
$scope.myData = {"1":120,"2":250,"3":500};
Function that iterates into object's properties and sum the price:
//read object properties and sum price
$scope.calculateSum = function(data){
var sum=0;
var counter=0;
for (var property in data) {
if (data.hasOwnProperty(property)) {
sum += data[property];
counter++;
}
}
return sum;
};
Function that iterates into object properties and count the products
//read object properties and count the products
$scope.countProducts = function(data){
var counter=0;
for (var property in data) {
if (data.hasOwnProperty(property)) {
counter++;
}
}
return counter;
};
Into your HTML template:
<table>
<tr ng-repeat="(key,value) in myData track by $index">
<td>
<input type="text" name="id" ng-model="key" class="form-control">
</td>
<td>
<input type="text" name="price" ng-model="value" class="form-control">
</td>
</tr>
<tr>
<td>Products: {{countProducts(myData)}}</td>
<td>Sum: {{calculateSum(myData)}}</td>
</tr>
</table>
I have done a live example that counts the products and also sum the products price: http://plnkr.co/edit/FmJhvV?p=preview
Hope helps, good luck.
I have a table 'mytable' that looks like:
<tr>
<td><input type="checkbox" name="check[]" value="11"></td>
<td>11</td>
<td>2014-11-06 18:49:26</td>
<td>MESSAGE</td>
<td></td>
<td>MATCH5</td>
<td>NO MATCH</td>
<td>NO MATCH</td>
</tr>
I want to get the value of column 4 "MESSAGE" from a row if its checked. In How to get value of table cell with jquery from checkbox using absolute row number it was shown that
var ids = $('table input:checked').map(function(){
return $(this).closest('tr').find('td:eq(3)').text();
});
returns
Object["MESSAGE"]
How can I get just the contained text/html ?
Call get() at the end, to get an array. The values will be in that array.
var ids = $('table input:checked').map(function(){
return $(this).closest('tr').find('td:eq(3)').text();
}).get();
Otherwise, you just have a jQuery collection pointing to a bunch of strings.
I want to add a row in the table on click of "Add" button.I am trying to accomplish this using "ng-show" directive but that row is displaying even without clicking "Add" button. Please help me with this. Here is the code -
home.html -
<table class="table">
<thead>
<tr>
<th>SNo.</th>
<th>UserId</th>
<th>Name</th>
<th>Share</th>
<th>Paid</th>
</tr>
</thead>
<tbody ng-repeat="member in members">
<tr>
<td>{{member.sNo}}</td>
<td>{{member.id}}</td>
<td>{{member.name}}</td>
<td>{{member.share}}</td>
<td>{{member.paid}}</td>
</tr>
<tr ng-show="show" class="ng-hide"> //the row which is to be added
<td><span>{{counter}}</span></td>
<td><input type="text" required ng-model="new.id"></td>
<td><input type="text" required ng-model="new.name"></td>
<td><input type="text" required ng-model="new.share"></td>
<td><input type="text" required ng-model="new.paid"></td>
</tr>
</tbody>
</table>
<div><input type="button" value="Add" ng-click="addMember()"/></div>
controller.js -
expmodule.controller('expenseForm', function($scope, sharedProperties) {
var id, expenses = {};
$scope.show = false;
$scope.members = [{
sNo: "1",
id: "abc#gmail.com",
name: "Neha",
share: 200,
paid: 400,
}, {
sNo: "2",
id: "xyz#gmail.com",
name: "Sneha",
share: 200,
paid: 400,
}];
$scope.counter = $scope.members.length++;
$scope.addMember = function () {
$scope.show = true;
return $scope.newRow = true;
}
});
Are you looking for something like this? http://plnkr.co/edit/jxXX5sWhgmYrANV7ieKM?p=preview
There are few things which are not correct in the code provided in the question.
The add row is inside ng-repeat. So a new add row will be added for each member.
Also as the show variable is inside ng-repeat it will be a child of parent scope and will be always false as per the current logic.
$scope.counter = $scope.members.length++ This will increase the array length by 1 and the new object in the array will be undefined. I guess you wanted to display the counter in the new add row. It can be simple done like this - {{members.length + 1}} in the add row rather than creating a new scope variable for this. Also this will always have the latest value when ever a new member is added.
The return statement in the addMember function has a assignment operation.
It seems to work fine (see demo below).
Of course, you should place the ng-repeat="member in members" to the <tr> not <tbody> (unless you want to have multiple tbodies).
And you should change $scope.counter = $scope.members.length++; to $scope.counter = $scope.members.length + 1;
See, also, this short demo.