I have an angular app in this plunker
I have a text area which has some text in the format of (key,count) in them by default.
What i am trying to achieve is this(in the calc() function):
When the button is pressed the results of the summation should be displayed.
I was able to split the data from the textarea into different arrays but i am missing the logic to add when the names match.
EDIT:
please notice a few updates in my plunker
New to angular and javascript!
This should do it.
JS:-
$scope.calc = function() {
$scope.users = {};
$scope.values.split('\n').forEach(function(itm){
var person = itm.split(','),
name,
key;
if(! itm.trim() || !person.length) return;
name = person[0].trim()
key = name.toLowerCase();
$scope.users[key] = $scope.users[key] || {name:name, count:0};
$scope.users[key].count += +person[1] || 0;
});
}
HTML:-
<div class="alert alert-success" role="alert">
<ul>
<li ng-repeat="(k,user) in users">The total for {{user.name}} is {{user.count}}</li>
</ul>
</div>
Demo
Add shim for trim() for older browsers.
Here's another way to do it. I can't speak to performance against PSL's method, but I think this reads a little easier to my not-very good at javascript eyes.
function groupByName(names) {
inputArray = names.split('\n');
outputArray = {};
for (i = 0; i < inputArray.length; i++) {
var keyValuePair = inputArray[i].split(',');
var key = keyValuePair[0];
var count = Number(keyValuePair[1]);
// create element if it doesnt' exist
if (!outputArray[key]) outputArray[key] = 0;
// increment by value
outputArray[key] += count;
}
return outputArray;
}
This will produce an object that looks like this:
{
"John": 6,
"Jane": 8
}
You can display the name of each property and it's value with ng-repeat:
<li ng-repeat="(key, value) in groupedNames">
The total for {{key}} is {{value}}
</li>
It's not an overwhelmingly complex bit of javascript, depending on the number of name value pairs. So you can probably even get rid of the manual calc button and just put a $watch on values in order to automatically recalculate totals with every change.
$scope.$watch('values', function() {
$scope.groupedNames = groupByName($scope.values);
});
Demo in Plunker
You can build a TotalArray with the actual name (key) of your input as key and the count as value with it. Iterate over the input pairs and check if there is already a key called the key of this iteration if so: add the count to its value, otherwise create a new one in the TotalArray.
Some pseudo code that might help you:
inputArray = text.split('\n')
outputArray = []
for(i = 0, i< length, i++) {
name = inputArray[i].split(',')[0]
count = inputArray[i].split(',')[1]
if (outputArray[name] exists) {
outputArray[name] += count
} else {
outputArray[name] = count
}
}
Now outputArray contains [[name1] => total_count1, [name2] => total_count2,... ]
I hope this helps you.
Related
I need add row in datatable, but the number the colums is variable.
I try two each but not run because row.add need all row not 1 to 1.
var obj = $.parseJSON(res);
$.each(obj, function (index) {
$.each(obj[index], function (value) {
table.row.add([obj[index][value]]).draw();
});
});
Is possible add row without knowing the number of columns?
Edit:
So If you have a variable number of columns the only way you'd be able to still use the datatable most likely is by inserting blank values into the columns of rows which don't posess the maximum amount of values, ex:
table.row.add(['a','b','c','d']).draw();
//Above is a row which has all the 4 column values
//Beneath is a row with 3 out of 4 column values
table.row.add(['a','b',null,'d']).draw()
/*or*/
table.row.add(['a','b','','d']).draw()
I'm not quite sure where you've gotten the idea that row.add() needs all rows added at once.
https://datatables.net/reference/api/row.add() according to the official documentation this method is able to add single rows to your table without any problem.
Here a JSFiddle proving that a single row can be added to the already existing ones:
myTable.row.add(["Airi Satou", "This was", "added", "later", "EXAMPLE", "ITEM"]).draw();
http://jsfiddle.net/bbLjzspf/8709/
Firstly, there is an error in your script, perhaps a typo, there is an extra square bracket after [obj][index][value] "]".
var obj = $.parseJSON(res);
$.each(obj, function (index) {
$.each(obj[index], function (value) {
table.row.add(
[obj[index][value] >]<-- One too many brackets ).draw();
});
});
Then my suggestion.
First I make two little helpers...
One to count the number of columns:
$.fn.DTbl_columnCount = function () {
return $('th', $(this).find('thead')).length;
};
And since I've got no idea what kind of data is coming, the next one is all belts and buckles, erm, in a "whatever" version, that also accepts arrays ;)
$.fn.DTbl_createDataColumns = function (whatever) {
var temp = new Array($(this).DTbl_columnCount());
var value = "";
var type = jQuery.type(whatever);
var isArray = (type == "array");
if (!isArray && type != undefined)
value = whatever;
for (var i = 0; i < temp.length; i++) {
if (isArray)
if (whatever.length > i)
value = whatever[i];
temp[i] = '' + value;
value = "";
}
return temp;
};
And then to your problem, since these additions are not really part of DataTables we need to fetch the DataTable Id in the function call of DTbl_createDataColumns, here using the standard reference "#example".
var obj = $.parseJSON(res);
$.each(obj, function (index) {
$.each(obj[index], function (value) {
table.row.add(
$("#example").DTbl_createDataColumns([obj[index][value])
).draw();
});
});
So this would also work:
var myArray = ["Dodaa", "Dodee"];
table.row.add( $("#example").DTbl_getDataColumns(myArray) );
table.row.add(['a','b','','d']).draw()
didn't work for me.
I have to do
table.row.add([['a','b','','d']]).draw()
Also it is important to be consistent between data types of dictionary and array. DataTable does NOT like it if we mix dictonaries and arrays in different calls. For example we might need to do (if it is initialized with an array of dictionaries).
table.row.add([{'hdrCol1': 'a', 'hdrCol2':'b','hdrOfCol3':'', 'hdrCol4':'d'}]).draw()
I have multiple checkboxes in a view and each one has some data attributes, example:
Once the button is clicked I'm iterating through all the checkboxes which are selected and what I want to do is get the data-price and value fields for each selected checkbox and create JSON array.
This is what I have so far:
var boxes2 = $("#modifiersDiv :checkbox:checked");
var selectedModifiers = [];
var modifierProperties = [];
for (var i = 0; i < boxes2.length; i++) {
for (var k = 0; k < boxes2[i].attributes.length; k++) {
var attrib = boxes2[i].attributes[k];
if (attrib.specified == true) {
if (attrib.name == 'value') {
modifierProperties[i] = attrib.value;
selectedModifiers[k] = modifierProperties[i];
}
if (attrib.name == 'data-price') {
modifierProperties[i] = attrib.value;
selectedModifiers[k] = modifierProperties[i];
}
}
}
}
var jsonValueCol = JSON.stringify(selectedModifiers);
I'm not able to get the values for each checkbox and I'm able to get the values only for the first one and plus not in correct format, this is what I'm getting as JSON:
[null,"67739",null,"1"]
How can I get the correct data?
You can use $.each to parse a jquery array, something like:
var jsonValueObj = [];
$("#modifiersDiv :checkbox:checked").each(function(){
jsonValueObj.push({'value':$(this).val(),'data-price':$(this).attr('data-price')});
});
jsonValueCol = JSON.stringify(jsonValueObj);
Please note it's generally better to use val() than attr('value'). More information on this in threads like: What's the difference between jQuery .val() and .attr('value')?
As for your code, you only had one answer at most because you were overwriting the result every time you entered your loop(s). Otherwise it was okay (except the formatting but we're not sure what format you exactly want). Could please you provide an example of the result you would like to have?
if you want to get an object with all checked values, skip the JSON (which is just an array of objects) and make your own....
var checked =[];
var getValues = function(){
$('.modifiers').each(function(post){
if($(this).prop('checked')){
checked.push({'data-price':$(this).attr('data-price'),'value':$(this).attr('value')});
}
});
}
getValues();
sure i'm missing something obvious here.. but mind is elsewhere
This should give an array with values (integers) and prices (floats):
var selected = [];
$("#modifiersDiv :checkbox:checked").each(function()
{
var val = parseInt($(this).val(), 10);
var price = parseFloat($(this).data("price"));
selected.push(val);
selected.push(price);
});
Edit: Updated answer after Laziale's comment. The $(this) was indeed not targeting the checked checkbox. Now it should target the checkbox.
I have indexed a bunch of inputs in my html form.
I want to loop through the inputs and create an array. From that array I want to collect the total (sum) of the fields and finally append another HTML input to display that total.
I know how to do this in PHP but I am struggling with JavaScript and I need it done client side.
I have tried to construct as much of this as possible. Here is a jsFiddle:
Here is my html:
<div style="padding:5px;clear:both;"><input type="text" name="total_inkind" id="total_inkind" placeholder="$" onchange="calcInKind()"></div>
and Javascript:
function calcInKind() {
var runningTotal = 0;
var i = 0;
for (var i = 0; document.getElementById('inkind').value; i++){
if(document.getElementById('inkind').value != ''){
$gwyl_gr = document.getElementById('inkind').value;
$runningTotal = parseFloat($runningTotal) + parseFloat($gwyl_gr);
}else{
$gwyl_gr = 0;
}
i = i++;
}
document.getElementById('total_inkind').value = $runningTotal;
}
For something as simple as a sum of all the form elements, you don't really need an array unless you want to manipulate every value in more ways than one. You can however loop over every input you had in the form, taking its value and adding it to the total.
Looking at your code however, I have to remark that Javascript does not require variables to be preceded by a $ unlike PHP. You however have the opportunity to use them, which JQuery users often do, to denote that their variable is in fact a JQuery variable.
I forked your JSFiddle and rewrote some things to get it working as the question states: JSFiddle
function sumTheInkinds() {
var runningTotal = 0;
var ourlist = document.getElementsByClassName("inkind");
for (var i = 0; i < ourlist.length; i++) {
if (ourlist[i].value != '') {
try {
runningTotal = runningTotal + parseFloat(ourlist[i].value);
} catch (err) {
alert ("Value was not a float!");
}
}
}
document.getElementById('total_inkind').value = runningTotal;
};
document.getElementById("runcalc").onclick = sumTheInkinds;
My implementation however relies on a button press which may not be intended, which can easily be changed back to onchange by applying this:
var inks = document.getElementsByTagName("inkind");
for (var i=0;i<inks.length;i++) {
inks.onchange = sumTheInkinds;
}
jQuery.get("ChkNewRspLive.php?lastmsgID=" + n, function(newitems){
//some code to separate values of 2d array.
$('#div1').append(msgid);
$('#div2').append(rspid);
});
Let's say the value of newitems is [["320","23"],["310","26"]]
I want to assign "320" and "310" to var msgid.
I want to assign "23" and "26" to var rspid.
How to do that?
I tried to display newitems and the output is "Array". I tried to display newitems[0] and the output is blank.
If I redeclare var newitems = [["320","23"],["310","26"]]; it works. So I guess the variable newitems from jQuery.get is something wrong. Is it I cannot pass the array from other page to current page through jQuery directly?
Regarding the array on other page, if echo json_encode($Arraytest); the output is [["320","23"],["310","26"]] but if echo $Arraytest; the output is Array. How do I pass the array from other page to currently page by jQuery.get?
I don't totally understand the question but I'm going to assume you want the values in an array, as two values can't be stored in one (scalar) variable simultaneously.
jQuery.get("ChkNewRspLive.php?lastmsgID=" + n, function(newitems){
//some code to separate values of 2d array.
var msgid = [],
rspid = [];
for( i = 0 ; i < newitems.length ; i++){
msgid[msgid.length] = newitems[i][0];
rspid[rspid.length] = newitems[i][1];
}
//msgid now contains ["320","310"]
//rspid now contains ["23","26"]
});
Bear in mind those are in the function scope. If you want to use them outside of that scope instantiate them outside. see: closure
You can use pluck from underscore.js: http://documentcloud.github.com/underscore/#pluck
var msgid = _(newitems).pluck(0)
var rspid = _(newitems).pluck(1)
Try this:
function getArrayDimension(arr, dim) {
var res = [];
for(var i = 0; i < arr.length; i++) {
res.push(arr[i][dim]);
}
return res;
}
var newitems = [["320","23"],["310","26"]];
var msgid = getArrayDimension(newitems, 0);
var rspid = getArrayDimension(newitems, 1);
msgid and rspid are arrays holding the 'nth' dimention.
Tnx
Given the following HTML form:
<form id="myform">
Company: <input type="text" name="Company" value="ACME, INC."/>
First Name: <input type="text" name="Contact.FirstName" value="Daffy"/>
Last Name: <input type="text" name="Contact.LastName" value="Duck"/>
</form>
What is the best way serialize this form in javascript to a JSON object in the format:
{
Company:"ACME, INC.",
Contact:{FirstName:"Daffy", LastName:"Duck"}
}
Also note that there might be more than 1 "." sign in the field name.
I think that what you'd do is this: for each input, first split the name at the separators (the '.' characters). Now, you have an array of names. You can then iterate through that array, making sure that your target "assembly" object (and sub-objects) have containers every time you come across a new name segment. When the array has 1 element in it, you simply add the value.
$.fn.extractObject = function() {
var accum = {};
function add(accum, namev, value) {
if (namev.length == 1)
accum[namev[0]] = value;
else {
if (accum[namev[0]] == null)
accum[namev[0]] = {};
add(accum[namev[0]], namev.slice(1), value);
}
};
this.find('input, textarea, select').each(function() {
add(accum, $(this).attr('name').split('.'), $(this).val());
});
return accum;
});
// ...
var object = $('#myform').extractObject();
I just sort-of made that up so there might be a bug or two; I can't remember whether all the browsers have "slice" but I think they do.
(edit: I forgot the all-important call to split())
You can loop through the form fields by name, use String#split to split the names on dot, and build up your resulting structure. Concept code:
function serializeDeep(form) {
var rv, obj, elements, element, index, names, nameIndex, value;
rv = {};
elements = form.elements;
for (index = 0; index < elements.length; ++index) {
element = elements[index];
name = element.name;
if (name) {
value = $(element).val();
names = name.split(".");
obj = rv;
for (nameIndex = 0; nameIndex < names.length; ++nameIndex) {
name = names[nameIndex];
if (nameIndex == names.length - 1) {
obj[name] = value;
}
else {
obj = obj[name] = obj[name] || {};
}
}
}
}
return rv;
}
Note that that doesn't allow for fields with repeated names (which should create arrays), nor does it elegantly handle a situation where you use the names "foo" and "foo.bar". But it should get you started.
I have managed it this way:
$('#Myform').attr('onsubmit', 'test()');
function test() {
var obj = {};
obj.title =$('#title').prop('value');
console.log('title: '+obj.title);
obj.website =$('#website').prop('value');
console.log('website: '+obj.website);
obj.tags =$('#tags').prop('value').split(',');
console.log('tags: '+obj.tags);
do_something(JSON.stringify(obj));
}
Of course this can be done if you know what the names are, and I am in fact generating the table itself using Formation plug-in.
I created an example for this question by using plain js, please check developer tool console to see the data object!
jsfiddle example
var data = {};
var array = 'person.name.first'.split('.');
var value = 'myFirstName';
generateObj(data, array, value);
console.log(data);
function generateObj(obj, arr, val) {
if (arr.length === 1) {
obj[arr[0]] = val
return;
}
var restArr = arr.splice(1);
if (!obj[arr[0]]) {
obj[arr[0]] = {};
}
generateObj(obj[arr[0]], restArr, val);
}
solution:
transform each name string to array.
iterate through each array.
recursively call a method which create an obj and set this obj as the value of the property and pass this obj to the next recursion.
Create an object of that shape then use a JSON encoder to write it out.