I have some javascript that is fetching some JSON and I'm trying to combine certain rows of information together to use in a table.
The JSON looks like below:
[{"Code":"12345","Name":"foo","Service":"Payments"},
{"Code":"12345","Name":"foo","Service":"Marketing"},
{"Code":"23456","Name":"bar","Service":"Payments"},
{"Code":"23456","Name":"bar","Service":"Development"},
{"Code":"34567","Name":"baz","Service":"Marketing"}]
Basically some rows share the exact same information with each other except for one field, Service.
My thought was to try to turn each row into an object that I can either update or merge with another object that shares the same Code.
That object and code looks something like this:
function CustObj(code,name,hasPay,hasMarket,hasDev) {
this.code = code;
this.name = name;
this.hasPay = hasPay;
this.hasMarket = hasMarket;
this.hasDev = hasDev;
}
function formatData(data) {
var formatedData = [];
for (var key in data) {
var customer = new CustObj(data[key].Code,data[key].Name);
switch (data[key].Service) {
case 'Payments':
customer.hasPay = true;
break;
case 'Marketing':
customer.hasMarket = true;
break;
case 'Development':
customer.hasDev = true;
break;
}
formatedData.push(school);
}
}
The problem is that I want to have one object for each unique Code but that has the correct amount of flags based on Service but I haven't figured out how to do that yet. I was looking at doing something like $.extend(formatedData,customer) to merge objects but I can't seem to get the right logic for locating the two objects that I'm trying to merge.
Any thoughts on how this can be accomplished?
You can process the array for duplicates and create a new array where the "Service" property is an array of services that share the same Code and Name:
var data = [
{"Code":"12345","Name":"foo","Service":"Payments"},
{"Code":"12345","Name":"foo","Service":"Marketing"},
{"Code":"23456","Name":"bar","Service":"Payments"},
{"Code":"23456","Name":"bar","Service":"Development"},
{"Code":"34567","Name":"baz","Service":"Marketing"}
];
function mergeServices(data) {
var result = [], item, match, found;
// for each array item
for (var i = 0; i < data.length; i++) {
item = data[i];
found = false;
for (var j = 0; j < result.length; j++) {
// see if we have a dup of a previously existing item
if (item.Code == result[j].Code && item.Name == result[j].Name) {
// just add the Service name to the array of the previous item
result[j].Service.push(item.Service);
found = true;
break;
}
}
if (!found) {
// copy the current row (so we can change it without changing original)
var newItem = {};
for (var prop in item) {
newItem[prop] = item[prop];
}
// convert service to an array
newItem.Service = [newItem.Service];
result.push(newItem);
}
}
return result;
}
var output = mergeServices(data);
That produces this output:
[
{"Code":"12345","Name":"foo","Service":["Payments","Marketing"]},
{"Code":"23456","Name":"bar","Service":["Payments","Development"]},
{"Code":"34567","Name":"baz","Service":["Marketing"]}
]
Working jsFiddle: http://jsfiddle.net/jfriend00/6rU2z/
As you create your customers you can add them to a map (an object) so that they can be referenced by code. You only create customers that are not already in the map. For each row you get or create the corresponding customer and set the corresponding flag.
function formatData(data) {
var customerMap = {};
$(data).each(function(index, elem){
// Get the customer if it is already in the map, else create it
var customer = customerMap[elem.Code];
if(!customer) {
customer = new CustObj(elem.Code, elem.Name);
customerMap[elem.Code] = customer;
}
// Add flags as appropiate
switch (elem.Service) {
case 'Payments':
customer.hasPay = true;
break;
case 'Marketing':
customer.hasMarket = true;
break;
case 'Development':
customer.hasDev = true;
break;
}
});
// Convert map to array
var formatedData = [];
for(var code in customerMap){
formatedData.push(customerMap[code]);
}
}
function CustObj(code,name) {
this.code = code;
this.name = name;
this.hasPay = false;
this.hasMarket = false;
this.hasDev = false;
}
EDIT I've created a fiddle to demonstrate this
JSFiddle
Related
I have a grid in html with some data of example Directors. Then I change the data, and want to update db.
Using a JS function, I get all the details from the grid, and save it in an array.
function getDirectorGridDetails() {
var tableRows = document.getElementById("tc_directorsGrid_table").rows
for (var i = 0; i < tableRows.length; i++) {
var directorRow = tableRows[i]
if (directorRow) {
var directorRowSeq = directorRow.getAttribute("data-id");
var directorDetailDesc = directorRow.getElementsByTagName("td")[0].innerHTML;
var directorDetailGender = directorRow.getElementsByTagName("td")[1].innerHTML;
var directorDetailDateApp = directorRow.getElementsByTagName("td")[2].innerHTML;
var directorDetailDateRes = directorRow.getElementsByTagName("td")[3].innerHTML;
if (!x) {
var x = [];
var Seq = [];
var Description = [];
var Gender = [];
var DateAppointed = [];
var DateResigned = [];
}
Seq.push(directorRowSeq);
Description.push(directorDetailDesc);
Gender.push(directorDetailGender);
DateAppointed.push(directorDetailDateApp);
DateResigned.push(directorDetailDateRes);
}
else {
break;
}
}
var directorsclass = {
"directorsclass": {
"Seq": Seq,
"Description": Description,
"Gender": Gender,
"DateAppointed": DateAppointed,
"DateResigned": DateResigned
}
}
return directorsclass
};
then, when I enter my C# side, to get the details and update db, the class is only returning the first items of the array.
Is there a way of getting each object from array, pass that in to class?
c# code snippit
[HttpPost]
[Route("client/updateDirector")]
public ActionResult updateDirector([System.Web.Http.FromBody] DirectorsClass directorsclass)
{}
when it get to directorsclass, it only shows first element
I have two HTML inputs (type="email", type="number") and my Angular app watches them using $formatters and $parsers. The errors are stored in an array and when user insert an email which contains "#gmail" the error is removed from the array.
app.controller('form1Controller', function($scope, UserService) {
$scope.formCompleted = false;
$scope.errors = UserService.errors;
//handle the user email input.
$scope.storeEmailErr = function(data) {
var correctKey = "#gmail";
var key = "#userEmail";
var res = {};
if (data != null) {
res = $scope.handleError(data, emailIn, correctKey, key, $scope.errors);
$scope.errors = res[0];
UserService.errors = res[0];
emailIn = res[1];
}
};
//handle the user email input.
$scope.storeIdErr = function(data) {
var correctKey = "0000";
var key = "#userId";
var res = {};
if (data != null) {
res = $scope.handleError(data, idIn, correctKey, key, $scope.errors);
$scope.errors = res[0];
idIn = res[1];
}
};
}
This is the code that adds and removes errors from array. And here i suppose is the problem
function theIndexOf(val) {
console.log("find index in array of length: " + errorsDescription.length)
for (var i = 0; i < errorsDescription.length; i++) {
if (errorsDescription[i].selector === val) {
return i;
}
}
}
app.run(function($rootScope){
$rootScope.handleError = function(data, elemIn, correctKey, key, errorArray){
var idx = theIndexOf(key);
console.log("get index >>>>> " + idx);
var obj = errorsDescription[idx];
//if user didn't put correct word i.e. #gmail or 0000
if (data.indexOf(correctKey) < 0) {
if (!elemIn) {
errorArray.push(obj);
elemIn = true;
}
} else {
if (elemIn) {
$.each(errorArray, function(i){
if(errorArray[i].selector === key) {
errorArray.splice(i, 1);
elemIn = false;
}
});
}
}
return [errorArray, elemIn];
}
});
The problem is that when I insert i.e. "test#gmail.com", the error is deleted from the array and when I insert correct data again it tells me that cannot read 'yyy' property of undefined.
Here is my plunker.
https://plnkr.co/edit/l0ct4gAh6v10i47XxcmT?p=preview
In the plunker, type in the fields 'test#gmail' and test0000 for the Number, then remove data then insert again the same data to see the problem
Any help would be much appreciated!
EDIT: Working plunkr here: https://plnkr.co/edit/8DY0Cd5Pvt6TPVYHbFA4
The issue is here:
var obj = errorsDescription[idx];
//if user didn't put correct word i.e. #gmail or 0000
if(data.indexOf(correctKey) < 0){
// console.log("You must put correct word");
if(!elemIn){
errorArray.push(obj);
elemIn = true;
}
}
When your Personal Number error is removed, the logic above pushes undefined to your errorArray (because elemIn is false). Your storeIdErr methond:
$scope.storeIdErr = function(data){
var correctKey = "0000";
var key = "#userId";
var res = {};
if(data != null){
res = $scope.handleError(data, idIn, correctKey, key, $scope.errors);
$scope.errors = res[0];
idIn = res[1];
}
};
reads this value (res[0]) and stores it in $scope.errors which ultimately is iterated over on the next input event by:
function theIndexOf(val){
console.log("find index in array of length: " + errorsDescription.length)
for(var i = 0; i < errorsDescription.length; i++){
if(errorsDescription[i].selector === val){
return i;
}
}
}
due to your factory returning that object when asked for errors. To fix this, you should keep a static list that you never remove from which provides the error definitions. This is what you should refer to when you push to errorArray in your first code block.
The issue you are having is with this block of code here:
$.each(errorArray, function(i){
if(errorArray[i].selector === key) {
errorArray.splice(i, 1);
elemIn = false;
}
});
When you call splice, you are modifying the length of the array. $.each is looping over the length of the array, and is not aware of the length change. (I don't know the internal workings of $.each, but I'm guessing it caches the length of the array before starting, for performance reasons.) So, after you splice out the first error, the loop is still running a second time. At this point, errorArray[1] no longer exists, which is causing your undefined error.
See this question for reference: Remove items from array with splice in for loop
I have a javascript object as below
var mydata=[
{"Club":"Blackburn","EventNo":1,"Pnts":3,"CumPnts":0},
{"Club":"Blackburn","EventNo":2,"Pnts":1,"CumPnts":0},
{"Club":"Blackburn","EventNo":3,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":1,"Pnts":2,"CumPnts":0},
{"Club":"Preston","EventNo":2,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":3,"Pnts":2,"CumPnts":0},]
I want to update the object so that CumPnts contains a running points total for each Club as below
{"Club":"Blackburn","EventNo":1,"Pnts":3,"CumPnts":3},
{"Club":"Blackburn","EventNo":2,"Pnts":1,"CumPnts":4},
{"Club":"Blackburn","EventNo":3,"Pnts":4,"CumPnts":8},
{"Club":"Preston","EventNo":1,"Pnts":2,"CumPnts":2},
{"Club":"Preston","EventNo":2,"Pnts":4,"CumPnts":6},
{"Club":"Preston","EventNo":3,"Pnts":1,"CumPnts":7},]
Any help would be much appreciated
Here is a function that loops through the list and updates it after it's been added. But I suspect that the events come in one at a time so there could be another function that can look the cumPtns obj and take from that. Here is for the current list.
var cumData = {};
var mydata=[
{"Club":"Blackburn","EventNo":1,"Pnts":3,"CumPnts":0},
{"Club":"Blackburn","EventNo":2,"Pnts":1,"CumPnts":0},
{"Club":"Blackburn","EventNo":3,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":1,"Pnts":2,"CumPnts":0},
{"Club":"Preston","EventNo":2,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":3,"Pnts":2,"CumPnts":0}];
function updateMyData() {
for (var i = 0; i < mydata.length; i++) {
var item = mydata[i];
if(cumData[item.Club] == undefined) {
cumData[item.Club] = {};
cumData[item.Club] = item.Pnts;
} else {
cumData[item.Club] = cumData[item.Club] + item.Pnts;
}
mydata[i].CumPnts = cumData[item.Club];
};
console.log(mydata);
//if you want to return it you can have this line below. Otherwise the object is updated so you'll probably want to do something with it once it's updated. Call back maybe?
return mydata;
}
updateMyData();
The first time it encounters a team it adds it to an array and so does with the corresponding cumPnts, so we can keep track of whether we checked a team earlier or not.
var tmArr = [];
var cumArr = [];
for(var i = 0; i < mydata.length; i++) {
var elm = mydata[i];
var club = elm.Club;
var points = elm.Pnts;
var idx = tmArr.indexOf(club);
if(idx > -1) {
cumArr[idx] += points;
elm.CumPnts = cumArr[idx];
}
else {
elm.CumPnts = points;
tmArr[tmArr.length] = club;
cumArr[cumArr.length] = points;
}
}
jsfiddle DEMO
I'm trying to loop through a list of Invoices, and their Individual LineItem Values,
and in the end have an Ojbect of [object Arrays] with an Invoice Number and the total value for all line items per Invoice.
var objInvoiceLineItem = function (strInvoiceNo,strValue) {
this.InvoiceNo= strInvoiceNo;
this.Value = strValue;
}
//
var objAllInvoices = [];
//
function AddValueTo_objAllInvoices(myInvoice){
//don't know how to look and see if the Invoice exists?
//jQuery.inArray?
//for (var i = 0; i < objAllInvoices.length - 1; i++)?
if exists (myInvoice.InvoiceNo) = false{
var newObjInvoiceItem=
new objInvoiceLineItem(myInvoice.InvoiceNo, myInvoice.Value);
objAllInvoices.push(newObjInvoiceItem)
}
else{
//need help here please
var obj = getobject;
objAllInvoices.obj.Value += myInvoice.Value;
}
}
//
var Invoice1A = new objInvoiceLineItem("Invoice1",20);
var Invoice1B = new objInvoiceLineItem("Invoice1",50);
var Invoice2A = new objInvoiceLineItem("Invoice2",30);
AddValueTo_objAllInvoices(Invoice1A);
AddValueTo_objAllInvoices(Invoice1B);
AddValueTo_objAllInvoices(Invoice2A);
I think something like this will do what you want:
function AddValueTo_objAllInvoices(myInvoice)
{
for (var i = 0; i < objAllInvoices.length; i++)
{
if (objAllInvoices[i].InvoiceNo == myInvoice.InvoiceNo)
{
// invoice exists, update it and return
objAllInvoices[i].Value += myInvoice.Value;
return;
}
}
// if the invoice already existed, we would have returned in the loop
// so we wouldn't have ever gotten here, so the invoice must not exist.
// create it now:
var newObjInvoiceItem = new objInvoiceLineItem(myInvoice.Container, myInvoice.Value);
objAllInvoices.push(newObjInvoiceItem);
}
may be you can help me. How can I create global object and function that return object values by id?
Example:
var chat = {
data : {
friends: {}
}
}
....
/*
JSON DATA RETURNED:
{"users": [{"friend_id":"62","name":"name","username":"admin","thumb":"images/avatar/thumb_7d41870512afee28d91.jpg","status":"HI4","isonline":""},{"friend_id":"66","name":"Another name","username":"regi","thumb":"images/avatar/thumb_d3fcc14e41c3a77aa712ae54.jpg","status":"Всем привет!","isonline":"avtbsl0a6dcelkq2bd578u1qt6"},{"friend_id":"2679","name":"My name","username":"Another","thumb":"images/avatar/thumb_41effb41eb1f969230.jpg","status":"","isonline":""}]}
*/
onSuccess: function(f){
chat.data.friends = {};
for(var i=0; i< f.users.length;i++){
chat.data.friends.push(f.users[i])
}
}
How can I create a new function (It will return values by friend_id)?
get_data_by_id: function (what, friend_id) {
/*obj.what = getfrom_globalobject(chat.data.friends???)*/
}
Example of use:
var friend_name = get_data_by_id(name, 62);
var friend_username = get_data_by_id(username, 62);
var friend_avatar = get_data_by_id(thumb, 62);
Try:
get_data_by_id: function (what, friend_id) {
return chat.data.friends[friend_id][what];
}
... but use it like:
var friend_name = get_data_by_id('name', 62);
...and set up the mapping with:
for(var i=0; i< f.users.length;i++){
chat.data.friends[f.users[i].friend_id] = f.users[i];
}
You cannot .push() to an object. Objects are key => value mappings, so you need to use char.data.friends[somekey] = f.users[i];
If you really just want a list with numeric keys, make x5fastchat.data.friends an array: x5fastchat.data.friends = [];
However, since you want to be able to access the elements by friend_id, do the following:
onSuccess: function(f){
x5fastchat.data.friends = {};
for(var i=0; i< f.users.length;i++){
chat.data.friends[f.users[i].friend_id] = f.users[i]
}
}
get_data_by_id: function (what, friend_id) {
obj[what] = chat.data.friends[friend_id][what];
}
Note the obj[what] instead of your original obj.what: When writing obj.what, what is handled like a string, so it's equal to obj['what'] - but since it's a function argument you want obj[what].
Take a look at the following code. You can simply copy paste it into an HTML file and open it. click "go" and you should see the result. let me know if I did not understand you correctly. :
<script>
myObj = { "field1" : { "key1a" : "value1a" }, "field2" : "value2" }
function go()
{
findField(myObj, ["field2"])
findField(myObj, ["field1","key1a"])
}
function findField( obj, fields)
{
var myVal = obj;
for ( var i in fields )
{
myVal = myVal[fields[i]]
}
alert("your value is [" + myVal + "]");
}
</script>
<button onclick="go()">Go</button>
I would recommend using the friend objects rather than getting them by id and name.
DATA = {"users": [{"friend_id":"62","name":"name","username":"admin","thumb":"images/avatar/thumb_7d41870512afee28d91.jpg","status":"HI4","isonline":""},{"friend_id":"66","name":"Another name","username":"regi","thumb":"images/avatar/thumb_d3fcc14e41c3a77aa712ae54.jpg","status":"Всем привет!","isonline":"avtbsl0a6dcelkq2bd578u1qt6"},{"friend_id":"2679","name":"My name","username":"Another","thumb":"images/avatar/thumb_41effb41eb1f969230.jpg","status":"","isonline":""}]}
// simple data store definition
Store = {items:{}};
NewStore = function(items){
var store = Object.create(Store);
store.items = items || {};
return store
};
Store.put = function(id, item){this.items[id] = item;};
Store.get = function(id){ return this.items[id]; };
Store.remove = function(id){ delete this.items[id]; };
Store.clear = function(){ this.items = {}; };
// example
var chat = {
data : {
friends : NewStore()
}
}
// after data loaded
chat.data.friends.clear();
for( var i = 0; i < DATA.users.length; i += 1 ){
var user = DATA.users[i];
chat.data.friends.put( user.friend_id, user );
}
getFriend = function(id){ return chat.data.friends.get( id ); }
var friend = getFriend(66);
console.log(friend.name);
console.log(friend.username);
console.log(friend.thumb);