I have a JSON formed like you can see further below. I am having trouble looping through and defining the correct points to loop over, as I'm not that experienced with arrays in objects and complicated JSON.
What I'm mainly looking for is some pointers on the parse / toJSON parts of my collection, or other places I might be failing with this particular structure.
I am trying to loop over the values and output data from the event and the type name using backbone and dust. Normally I can just loop over my JSON by defining the collection in the view, e.g. calling this like so:
dust.render("dialog-decoderevents-items", { events : currentUser.eventList.toJSON() }, function(err, out) {
_this.$(".ab-tvg-prg-opt-future").append($(out));
});
That would normally allow me to just make a loop in dust and output data like this:
{#events}
{#tvProgram}{name}{/tvProgram}
{type}
{/events}
I have tried the dust examples using array and current context on this JSON and it will output something with no problem. I think the problem lies in what I define as the starting point of the model and collection.
I have both a parse function and a toJSON function in my collection now. But I also don't know what to define as an id on the model, since as you can see the id is defined inside the event, and not on the outside where I'd normally use it. Ideas? All the data is below.
JSON
{
"status": null,
"value": [
{
"event": {
"id": "RWtzdHJlbSBvcHBkcmFnZWxzZTxsZHR2cGQ+MTM2NDMwMDQwMDAwMDxsZHR2cGQ+MTM2NDMwNDAwMDAwMA==",
"name": "A glorious event",
"description": "Some long description about the event",
"startTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 13,
"minute": 20,
"seconds": 0
},
"endTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 14,
"minute": 20,
"seconds": 0
}
},
"type": "Party"
},
{
"event": {
"id": "Rmx5aW5nIFdpbGQgQWxhc2thPGxkdHZwZD4xMzY0MzA2NDAwMDAwPGxkdHZwZD4xMzY0MzEwMDAwMDAw",
"name": "A glorious event",
"description": "Some long description about the event",
"startTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 15,
"minute": 0,
"seconds": 0
},
"endTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 16,
"minute": 0,
"seconds": 0
}
},
"type": "Birthday"
},
{
"event": {
"id": "UG9pcm90PGxkdHZwZD4xMzY0MzE2NjAwMDAwPGxkdHZwZD4xMzY0MzE5NjAwMDAw",
"name": "A glorious event",
"description": "Some long description about the event",
"startTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 17,
"minute": 50,
"seconds": 0
},
"endTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 18,
"minute": 40,
"seconds": 0
}
},
"type": "Birthday"
},
{
"event": {
"id": "VGhlIEJpZyBCYW5nIFRoZW9yeTxsZHR2cGQ+MTM2NDMxOTAwMDAwMDxsZHR2cGQ+MTM2NDMyMDgwMDAwMA==",
"name": "A glorious event",
"description": "Some long description about the event",
"startTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 18,
"minute": 30,
"seconds": 0
},
"endTime": {
"year": 2013,
"month": 3,
"date": 26,
"hour": 19,
"minute": 0,
"seconds": 0
}
},
"type": "Birthday"
}]}
Model
var mainEvent = Backbone.Model.extend({
idAttribute : "id",
defaults : {
type: null,
event : {
id : null,
name: null,
description: null,
channelId: null,
startTime: null,
endTime: null
}
}
});
Collection
var eventCollection = Backbone.Collection.extend({
model: mainEvent,
parse : function(json, options) {
var retr = [], tmp;
if (json.status === ajaxStatus.success) {
switch(options.action) {
default:
retr = json.value;
break;
}
if (options.action === "events") {
currentUser.eventList = new eventCollection(retr, { action : "events" });
}
}
else if (json.status === ajaxStatus.notAuthenticated) {
currentUser.trigger("notLoggedIn");
return [];
}
return retr;
},
toJSON : function(){
var ret = this.constructor.__super__.toJSON.call(this);
// _.each(ret, function (item) {
// console.log('l1'+item);
// ret.push(item);
// });
return ret;
}
});
Idea after quickly reading over your issue (take it with a grain of salt as I've never used dust or backbone before):
Couldn't you just create a controller that stores a content array for each event object? That way, all you would have to do when you were extracting the JSON file is add each event to the controller, and iterate over that in your HTML. You could then extract the id with id = event[id] or something.
EDIT: Here's an example with AJAX, I know you're not using that but the parsing bit should at least be helpful:
function getParties() {
$.ajax({
url: 'json/party.json',
dataType: 'json',
async: false,
success: function(data) {
console.log("Data:", data.value);
for (var i=0, occurence; occurence = data.value[i]; i++) {
var event = {};
event.type = occurence.type;
for (var key in occurence.event) {
event[key] = occurence.event[key];
}
console.log("Event:", event);
// Do something with event... Maybe add to content array.
}
}
});
}
The "event" should now be in simple javascript. If you want to access a known field within it, you can say event["id"] for example. To iterate through all values, use the following loop.
for (var key in event) {
console.log("Key: " + key + ", Value: " + event[key]);
}
You also should be able to get the value with {id}, for example, in Backbone. Something similar works in Ember when the created "event" objects are pushed to some controller's content array, which is what I'm using.
Related
I would like to convert objects in JavaScript, but I'm not really sure of the best way to do it. I don't often code in the language so I don't really know much of the fundamentals- this is the object I get back from an API call in a React project:
{
"api": {
"results": 380,
"fixtures": [
{
"fixture_id": 65,
"league_id": 2,
"league": {
"name": "Premier League",
"country": "England",
"logo": "https://media.api-sports.io/football/leagues/2.png",
"flag": "https://media.api-sports.io/flags/gb.svg"
},
"event_date": "2018-08-10T19:00:00+00:00",
"event_timestamp": 1533927600,
"firstHalfStart": 1533927600,
"secondHalfStart": 1533931200,
"round": "Regular Season - 1",
"status": "Match Finished",
"statusShort": "FT",
"elapsed": 90,
"venue": "Old Trafford (Manchester)",
"referee": null,
"homeTeam": {
"team_id": 33,
"team_name": "Manchester United",
"logo": "https://media.api-sports.io/football/teams/33.png"
},
"awayTeam": {
"team_id": 46,
"team_name": "Leicester",
"logo": "https://media.api-sports.io/football/teams/46.png"
},
"goalsHomeTeam": 2,
"goalsAwayTeam": 1,
"score": {
"halftime": "1-0",
"fulltime": "2-1",
"extratime": null,
"penalty": null
}
}
]
}
}
I would like to convert it to this array (the array holds multiple objects):
[
{
"homeTeam": {
"id": 33,
"name": "Manchester United",
"teamId": 33
},
"awayTeam": {
"id": 46,
"name": "Leicester",
"teamId": 46
},
"outcome": {
"goalsScoredByAwayTeam": 2,
"goalsScoredByHomeTeam": 1
},
"resulted": true,
"type": "LEAGUE"
}
]
The teamId and id actually need to lookup another object before the final output.
I'm not sure what the best way to do it is. This is my function so far, trying to make use of optional chaining:
function convertFixturesToArray() {
fixturesStore.getFixtures()?.api?.fixtures?.length ? fixtures.api.fixtures.map(fixture => (
//TRANSFORMATION GOES IN HERE
)) : null;
}
You seem on the right track. It should be something like this (written in a slightly more modern JS)
convertFixturesToArray = () => fixturesStore.getFixtures()?.api?.fixtures?.map?.(fixture => {
//Do whatever check you need here with the fixture object
return {
homeTeam: { ...fixture.homeTeam },
awayTeam: { ...fixture.awayTeam },
outcome: {
goalsScoredByAwayTeam: fixture.goalsAwayTeam,
goalsScoredByHomeTeam: fixture.goalsHomeTeam,
},
type: 'LEAGUE',
resulted: true,
},
}) ?? [];
It looks like you're trying to get certain key/value pairs from your api response. With a mix of map, reduce, and find, you can get the values you're looking for by defining them in an array (i.e. desiredProps).
Of course, adding the "outcome" field and your other hardcoded fields would require a bit more logic on top of this. Boris' answer addresses this problem. I've taken a more flexible approach.
let apiResult = {
"fixtures": [
{
"prop1": "a1",
"prop2": "a2",
"prop3": "a3"
},
{
"prop1": "b1",
"prop2": "b2",
"prop3": "b3"
}
]
}
let desiredProps = ["prop2", "prop3"]
let result = apiResult.fixtures.map(x => {
return Object.keys(x).reduce((acc, curr) => {
if (desiredProps.find(y => y === curr)) {
acc[curr] = x[curr]
}
return acc
}, {})
})
console.log(result)
I am facing problem in getting values from rendered data in component that is already outputted on page render. What I need to do is, when someone types in data into text field, it should send it to database but taking that fields data from runtime data.
Currently, when I type something, it says undefined field etc.
This is not form data but a data that need to be update from text field.
So, if user write some xyz in text field, we need to update that data according to the id associated to that field.
I am not able to get data into: console.log(Id, projectId, userId, date, e.target.value)
I have used reduce method that serves the purpose but now I have another use case.
I dont want to set hidden fields as its not the right approach.
The problem is that when someone type data in text field, I need to get that text field data and associated id and respective data from it and pass it ti ajax call.
I need to send that data with ajax but as soon as I type something, it says undefined. I can easily get data from projects array but its of no use to me. I think array reduce method is not good for my use case.
Here is project array:
data = [
{
"id": 27,
"projectno": "007823",
"projectname": "non-A Project 2",
"dailyproof": 1,
"probability": "1.0",
"toleranceregistering": 2,
"customer_name": "Peter",
"user_id": "4",
"days_allocated": "231.0",
"days_real": "5.0",
"hours_real": "6.0",
"project_times": [
{
"id": 11,
"activity": "\"yht\"",
"date": "2020-04-28",
"hours": "2.0",
"project_id": 27,
"token": "\"trr\"",
"user_id": 4,
"created_at": "2020-04-22T12:36:55.479Z",
"updated_at": "2020-04-22T12:36:55.479Z"
},
{
"id": 12,
"activity": "\"yht\"",
"date": "2020-04-03",
"hours": "2.0",
"project_id": 27,
"token": "\"trr\"",
"user_id": 4,
"created_at": "2020-04-22T12:37:08.763Z",
"updated_at": "2020-04-22T12:37:08.763Z"
},
{
"id": 13,
"activity": "\"yht\"",
"date": "2020-04-14",
"hours": "2.0",
"project_id": 27,
"token": "\"dfg\"",
"user_id": 4,
"created_at": "2020-04-22T12:37:19.177Z",
"updated_at": "2020-04-22T12:37:19.177Z"
}
]
},
{
"id": 28,
"projectno": "007333",
"projectname": "non-A Project 2",
"dailyproof": 0,
"probability": "1.0",
"toleranceregistering": 2,
"customer_name": "Peter",
"user_id": "4",
"days_allocated": "231.0",
"days_real": "3.333333333333333333333333334",
"hours_real": "4.0",
"project_times": [
{
"id": 18,
"activity": "\"tgr\"",
"date": "2020-04-16",
"hours": "2.0",
"project_id": 28,
"token": "\"ujy\"",
"user_id": 4,
"created_at": "2020-04-22T12:39:41.465Z",
"updated_at": "2020-04-22T12:39:41.465Z"
},
{
"id": 19,
"activity": "\"ddd\"",
"date": "2020-04-11",
"hours": "2.0",
"project_id": 28,
"token": "\"fff\"",
"user_id": 4,
"created_at": "2020-04-22T12:39:55.020Z",
"updated_at": "2020-04-22T12:39:55.020Z"
}
]
},
{
"id": 29,
"projectno": "00721",
"projectname": "non-A Project 2",
"dailyproof": 1,
"probability": "1.0",
"toleranceregistering": 2,
"customer_name": "Peter",
"user_id": "4",
"days_allocated": "231.0",
"days_real": "5.0",
"hours_real": "6.0",
"project_times": [
{
"id": 22,
"activity": "\"cdf\"",
"date": "2020-04-11",
"hours": "2.0",
"project_id": 29,
"token": "\"fgff\"",
"user_id": 4,
"created_at": "2020-04-22T12:41:26.392Z",
"updated_at": "2020-04-22T12:41:26.392Z"
},
{
"id": 23,
"activity": "\"tg\"",
"date": "2020-04-15",
"hours": "2.0",
"project_id": 29,
"token": "\"ad\"",
"user_id": 4,
"created_at": "2020-04-22T12:41:38.747Z",
"updated_at": "2020-04-22T12:41:38.747Z"
},
{
"id": 24,
"activity": "\"ff\"",
"date": "2020-04-19",
"hours": "2.0",
"project_id": 29,
"token": "\"bbb\"",
"user_id": 4,
"created_at": "2020-04-22T12:41:47.500Z",
"updated_at": "2020-04-22T12:41:47.500Z"
}
]
},
{
"id": 30,
"projectno": "0074",
"projectname": "non-A Project 2",
"dailyproof": 1,
"probability": "1.0",
"toleranceregistering": 2,
"customer_name": "Peter",
"user_id": "4",
"days_allocated": "231.0",
"days_real": "3.333333333333333333333333334",
"hours_real": "4.0",
"project_times": [
{
"id": 25,
"activity": "\"ff\"",
"date": "2020-04-12",
"hours": "2.0",
"project_id": 30,
"token": "\"bbb\"",
"user_id": 4,
"created_at": "2020-04-22T12:42:09.385Z",
"updated_at": "2020-04-22T12:42:09.385Z"
},
{
"id": 26,
"activity": "\"rter\"",
"date": "2020-04-19",
"hours": "2.0",
"project_id": 30,
"token": "\"gfdg\"",
"user_id": 4,
"created_at": "2020-04-22T12:42:19.861Z",
"updated_at": "2020-04-22T12:42:19.861Z"
}
]
}
]
getDaysNumber('2020', '04') {
const dayNums = [];
const daysInMonth = new Date(year, month, 0).getDate();
for (let i = 1; i <= daysInMonth; i++) {
dayNums.push(i);
// console.log(i, ' xxx ');
}
return dayNums;
}
{
data.map((h, index) => (
<TableRow key={`mi-${index}`}>
<TableCell align="right">{h.projectno}</TableCell>
<TableCell align="right">{h.projectname}</TableCell>
<TableCell align="right">{h.customer_name}</TableCell>
<TableCell align="right">{h.days_allocated}</TableCell>
<TableCell align="right">{h.days_real}</TableCell>
<TableCell align="right">{h.hours_real}</TableCell>
{daysNumber.reduce((acc, number, index) => {
const found = h.project_times.find(item => number == item["date"].split('-')[2].replace(/^0+/, ''))
const Id = found && found["id"];
const projectId = found && found["project_id"];
const userId = found && found["user_id"];
const date = found && found["date"];
const hours = found && found["hours"];
found && console.log(Id, projectId, userId, date);
return [...acc,
h.dailyproof == 1 && hours > 0.0 ?
<TableCell align="right" key={`mi-${index}`}
onClick={this.launchCreateContactDialog}>{hours}</TableCell>
:
<TableCell align="right" key={`mi-${index}`}>
<TextField required fullWidth size="small"
variant="outlined"
onKeyUp={(e) => console.log(Id, projectId, userId, date, e.target.value)}/>
</TableCell>
]
}, [])
}
</TableRow>
))
}
This find call may sometimes return undefined.
const found = h.project_times.find(item => number == item["date"]
.split('-')[2]
.replace(/^0+/, '')
)
This is expected when no matches are found. And since it's undefined, all of these will also end up undefined:
const Id = found && found["id"];
const projectId = found && found["project_id"];
const userId = found && found["user_id"];
const date = found && found["date"];
const hours = found && found["hours"];
Therefore, it's not unusual that your console.log statement will log out the value undefined.
It sounds like you're needing to do a few things:
Maintain this data as state in your component.
Add a function to mutate this state.
Add a function to store the state (calling an API)
I don't have enough context to answer #3 for you, but here's the type of pattern you want to go for:
import { useEffect, useState } from 'react';
function HoursEntry() {
const [state, setState] = useState();
useEffect(() => {
// Do your data fetching here; for now will use your constant
setState(data);
}, []);
function updateHours({ userId, projectId, hourEntryId, date, hours }) {
// Build newData based on the changes...
setState(newData);
}
// All the rendering stuff. Rendered components should be mappings of what's in
// state...
<TextField
required fullWidth
size="small"
variant="outlined"
value={hours}
onChange={(e) => updateHours({
userId,
projectId,
hourEntryId: Id,
date,
hours: parseFloat(e.target.value)
})}/>
// ...
}
Inside of your updateHours function, you'll create a new copy of your data with the expected modifications. For example, if you're updating an existing object, you'll update its hours property. If you're updating something for which there is no record, you'll create a new one, etc. The key is your call to setState to update the data in your component.
Then, once you have your submit button or whatever method you've got to store, you'll reference this state for the latest copy of your data.
That's the general pattern for any kind of form entry component; it's an exercise in updating state.
I have used Lodash to get to this structure where i needed to group by id .
The grouping by works fine but i want to add more properties to the head of the group by field like its name and domain, from the nested object , how do i do that.
Extra - Also In future if i need to Filter the contents inside the nested object like using status or by the publisher name how do i add that . Very new to Javascript
let result = _.chain(value)
.groupBy('pubId')
.pairs()
.map(function(currentItem) {
return _.object(_.zip(['publisherId', 'targetting'], currentItem));
})
.value();
The data returned by this
{
"publisherId": "17",
// add name , domain , here
"targetting": [
{
"id": 1,
"pubId": 17, // remove this
"type": 18,
"value": "google.com,yahoo.com",
"status": 12,
"createTs": null, // remove this
"updateTs": null,// remove this
"createUser": null,// remove this
"updateUser": null,// remove this
"percentage": 0,// remove this
"rtbSspPublishers": { // remove this
"id": 17,
"name": "Tom's Hardware",
"domain": "www.tomshardware.com",
"extPublisherId": 17
}
},
{
"id": 2,
"pubId": 17,
"type": 14,
"value": "Sports,Fashion",
"status": 12,
"createTs": null,
"updateTs": null,
"createUser": null,
"updateUser": null,
"percentage": 0,
"rtbSspPublishers": {
"id": 17,
"name": "Tom's Hardware",
"domain": "www.tomshardware.com",
"extPublisherId": 17
}
},
{
"id": 3,
"pubId": 17,
"type": 11,
"value": "Sports,Fashion",
"status": 12,
"createTs": null,
"updateTs": null,
"createUser": null,
"updateUser": null,
"percentage": 0,
"rtbSspPublishers": {
"id": 17,
"name": "Tom's Hardware",
"domain": "www.tomshardware.com",
"extPublisherId": 17
}
}
]
}
I need to remove certain properties from the nested grouping how do i acheive that using lodash i am using lodash 3.0.0 .Please help thanks
Just iterate the result again and delete those properties which are not required.
For example
var propsToBeDeleted = [ "createTs", "updateTs" ]; //array of properties to be deleted
result = result.map( function(item){
propsToBeDeleted.forEach( function(prop){
delete item[prop];
});
return item;
});
Or try updating your lodash code as
let result = _.chain(value)
.groupBy('pubId')
.pairs()
.map(function(currentItem) {
var item = _.object(_.zip(['publisherId', 'targetting'], currentItem));
propsToBeDeleted.forEach( function(prop){
delete item[prop];
});
return item;
})
.value();
I am trying to group this JSON by using BroadCategory attribute of category
[{
"brand": "Brand3",
"category": {
"popularity_index": 7,
"BroadCategory ": "BroadCategory4",
"MainCategory": "MainCategory410",
"GeneralCategory": "GeneralCategory41"
},
"description": "colonialism",
"discount": 17,
"id": 9
}, {
"brand": "Brand2",
"category": {
"popularity_index": 5,
"BroadCategory ": "BroadCategory2",
"MainCategory": "MainCategory210",
"GeneralCategory": "GeneralCategory21"
},
"description": "desc2",
"discount": 15,
"id": 2
}]
I went through underscore.js - _.groupBy nested attribute but this has array inside JSON for location
I tried something like:
var grpArray = _.groupBy(products, function (element) {
return element.category.BroadCategory;
})
but its not working. Why can't I access BroadCategory ?
You have to trim a space "BroadCategory "
"BroadCategory ": "BroadCategory2",
Change to:
"BroadCategory": "BroadCategory2",
OR:
_.groupBy(products, function (element) {
return element.category['BroadCategory '];
})
I currently have the following array in javascript
var chart1data = [
{ "Time": "1", "Temperature": 60, },
{ "Time": "2", "Temperature": 50, },
{ "Time": "3", "Temperature": 42, },
{ "Time": "4", "Temperature": 35, },
{ "Time": "5", "Temperature": 28, },
{ "Time": "6", "Temperature": 24, },
{ "Time": "7", "Temperature": 21, },
{ "Time": "8", "Temperature": 19, },
{ "Time": "9", "Temperature": 18, },
{ "Time": "10", "Temperature": 18, },
];
I have a button, in my HTML which when pressed, should change the value "60" in the above array to another number (for example - 80)
The button links to this function. How can I make it so this works?
function updatechart (){
//This gets the number from a text box
var inputdata1 = document.getElementById("textbox1").innerHTML
//Now I need the code to put this number in replace of the value "60"
}
You can update your array as follows:
chart1data[index].Temperature = inputdata1;
Fiddle: http://jsfiddle.net/KyleMuir/sPTG8/1/
Hope this helps
if you want to change 60 then:
chart1data[0].Temperature = inputdata1;
else
chart1data[index].Temperature = inputdata1;
Simply put, you have an array of object. Said objects contain 2 properties, Time and Temperature. To access an object within the array, assuming you know the index, you can do:
alert(chart1data[index].Time) // alerts the time of the first item
chart1data[index].Temperature = 60; // sets the temperature of the first item
Alternatively, if you want to replace all temperature values that are 60, you can loop through your items and simply update them, like so:
for (var i = 0; i < chart1data.length; i++) {
if (chart1data[i].Temperature == '60') {
chart1data[i].Temperature = '80'
}
}