Merging Data Objects in Javascript for Display in VueJS - javascript

first time question asker.
I am working on trying to bring together data from two different API endpoints being served from a Django Rest Framework backend and rendering the display with VueJS on the frontend.
The challenge I am faced with is merging my questionnaire sections and questions with the associated answers. The questionnaire information is coming from one endpoint and the answers from another. Below is a sample of the data.
Sections & Questions Data
{
"survey_id": 2,
"survey_name": "My Survey",
"instructions": "Instructions.",
"other_header_info": ""
"section": [
{
"section_id": 2,
"section_name": "Section Name",
"section_title": "Section Title",
"section_instructions": "Some Instructions",
"section_required_yn": true,
"question": [
{
"question_id": 2,
"question_name": "Question One.",
"question_subtext": "None.",
"answer_required_yn": true,
"input_type_id": {
"id": 3,
"input_type_name": "Dropdown"
},
"option_group_id": "1 - 10",
"allow_multiple_option_answers_yn": false
},
{
"section_id": 3,
"section_name": "Another Section",
"section_title": "Section Title",
"section_instructions": "Section Instructions",
"section_required_yn": true,
"question": [
{
"question_id": 10,
"question_name": "Another question to be answered",
"question_subtext": "None.",
"answer_required_yn": true,
"input_type_id": {
"id": 3,
"input_type_name": "Dropdown"
},
"option_group_id": "1 - 10",
"allow_multiple_option_answers_yn": false
},
Answers Data
"results": [
{
"id": 100,
"answer_numeric": 4,
"answer_text": null,
"answer_yn": null,
"answer_group": "4-ojepljuu",
"question_id": 2,
},
{
"id": 101,
"answer_numeric": 1,
"answer_text": null,
"answer_yn": null,
"answer_group": "4-ojepljuu",
"user_id": 4,
"question_id": 5,
},
I know I need to match up the question_id fields from both the questionnaire sections data and the answers data. The problem I am facing is, how does one go about doing this?
I would like to create a new set of data that appends the answer data to the question data. I am also trying to build in some flexibility since I have multiple survey types with a variable number of sections and questions.
Trying to keep the data in sections so I can render the frontend views the way I would like.
I've tried looping through sections and questions, using the example I found here: Merge two array of objects based on a key but haven't had much luck.
Still relatively new - any information, guidance or even a working example would be greatly appreciated.
Update:
I've managed to make a bit of progress on this. Writing a small test function, I can now update the section/question object with some dummy data.
var a = this.answers;
var s = this.section;
var newObj = { answer_text: "test1", answer_numeric: "test2" };
for (var idx3 = 0; idx3 < s.length; idx3++) {
for (var idx4 = 0; idx4 < s[idx3].question.length; idx4++) {
Object.assign(s[idx3].question[idx4], newObj);
}
}
Each of the question objects within each section now includes the answer_text and answer_numeric key/value pairs.
The next challenge is to find the matching answer data based on matching the appropriate question_id within the answer object to the question_id in the question object.
Any thoughts?

I would store results as a dictionary, instead of an array:
var results_to_dict = function (results) {
var dict = {};
results.forEach(r => dict[r.question_id] = r);
return dict;
};
results = results_to_dict(results);
Now, you can show your questions in your template with their answers:
<div v-for="question in section.questions" :key="question.question_id">
<p>Question: {{question.question_name}}</p>
<p>Answer: {{answers[question_id].text}}</p>
</div>

Related

Go through arrays of objects that contain arrays of objects

Backend sends an object that contains an array of objects. These objects contain more arrays of objects and so on. It resembles a tree.
I need to be able to go from one object to the other, following the array, and back. What would be the best way to do this in typescript?
I tried forEach, but I couldn't go back. For cycles inside of for cycles aren't an option either because sometimes there will be 2 levels of arrays, sometimes, 5. I thought of an iterator, but I don't know enough of angular/typescript to make it happen.
Here is a snippet of the data. This is a questionnaire and I need to show each question individually.
"questionId": 1,
"parent": null,
"description": "Question 1?",
"children":
[
{
"questionId": 2,
"parent": 1,
"description": "Question 2?",
"children":
[
{
"questionId": 4,
"parent": 2,
"description": "Question 4?",
"children": []
}
]
},
{
"questionId": 3,
"parent": 1,
"description": "Question 3?",
"children": []
}
]
Sorry if I'm explaining it poorly or something is missing, I'm not used to post here.
If you just want to iterate through all the question objects, you could try to flatten your data with a recursive function like this,
const flattenQs = (qData) => {
const flattenedQs = []
flattenedQs.push({questionId: qData.questionId, parent: qData.parent, description: qData.description})
for (let i = 0; i < qData.children.length; i++) {
const qChild = qData.children[i];
flattenedQs.push(...flattenQs(qChild))
}
return flattenedQs
}
Which would give something like this,
[
{
questionId:1,
parent:null,
description:"Question 1?"
},
{
questionId:2,
parent:1,
description:"Question 2?"
},
{
questionId:4,
parent:2,
description:"Question 4?"
},
{
questionId:3,
parent:1,
description:"Question 3?"
}
]

How do I create an unique dataset of json object literal in Javascript?

I want to get an output as an unique set of Categories array with the following output [Men,Woman].
Is there any way to do it in Javascript?
For example this my data
{
"products:"[
{
"id": 1,
"categories": {
"1": "Men",
},
},
{
"id": 2,
"categories": {
"1": "Men",
},
}, {
"id": 3,
"categories": {
"1": "Woman",
},
}
];
}
A simple 1 line answer would be
new Set(input.products.map(p => p.categories["1"]))
This is if you're expecting only key "1" in the categories object.
If it can have multiple categories then you can always do
const uniqueCategories = new Set();
input.products.forEach(p => uniqueCategories.add(...Object.values(p.categories)))
Now you can convert a Set into an array
PS: This is not a ReactJs problem but a pure JS question. You might want to remove the ReactJs tag from this question altogether.

JSON list optimization

I want to create a JSON API that returns a list of objects. Each object has an id, a name and some other information. API is consumed using JavaScript.
The natural options for my JSON output seems to be:
"myList": [
{
"id": 1,
"name": "object1",
"details": {}
},
{
"id": 2,
"name": "object2",
"details": {}
},
{
"id": 3,
"name": "object3",
"details": {}
},
]
Now let's imagine that I use my API to get all the objects but want to first do something with id2 then something else with id1 and id3.
Then I may be interested to be able to directly get the object for a specific id:
"myList": {
"1": {
"name": "object1",
"details": {}
},
"2": {
"name": "object2",
"details": {}
},
"3": {
"name": "object3",
"details": {}
},
}
This second option may be less natural when somewhere else in the code I want to simply loop through all the elements.
Is there a good practice for these use cases when the API is used for both looping through all elements and sometime using specific elements only (without doing a dedicated call for each element)?
In your example you've changed the ID value from 1 to id1. This would make operating on the data a bit annoying, because you have to add and remove id all the time.
If you didn't do that, and you were relying on the sorted order of the object, you may be in for a surprise, depending on JS engine:
var source = JSON.stringify({z: "first", a: "second", 0: "third"});
var parsed = JSON.parse(source);
console.log(Object.keys(parsed));
// ["0", "z", "a"]
My experience is to work with arrays on the transport layer and index the data (i.e. convert array to map) when required.

How to get last item from array of object? [duplicate]

This question already has answers here:
Get the last item in an array
(59 answers)
Closed 6 years ago.
I have JSON object from server and requirement is to always display last item from the array items. how can i achieve that task using AngularJs or native JavaScript ?
Below case i have to display text Chief Administrative Officer.
main.js
angular.forEach($scope.rcsaErhTreeData, function(val) {
angular.forEach(val, function(val) {
console.log('this is the array value', val[0].text);
});
});
json.js
[{
"uid": null,
"index": 0,
"selected": null,
"expanded": null,
"id": 2701,
"text": "BAC Enterprise Wide",
"parentId": 0,
"items": [{
"uid": null,
"index": 0,
"selected": null,
"expanded": null,
"id": 4114,
"text": "Chief Administrative Officer",
"parentId": 2701,
"items": []
}]
}]
if you try the following code in your context you will get the result.
console.log(JSON.stringify(items[items.length - 1]));
The console will show you the stringified output...
Thanks,
Paras
I am not a Angular.js programmer, but the concept would be to:
1. Either do it in a loop and overwrite the variable value with the next value, that way, the last one will persist. -- Not recommended due to performance issues, and using a loop when it can be done without a loop.
Pseudo code:
var outVal='';
angular.forEach($scope.rcsaErhTreeData, function(val) {
angular.forEach(val, function(val) {
outVal = val[0].text);
});
});
console.log('this is the last item value', outVal);
Another approach would be find the length of the val array, and go to its last index to fetch its value. I am not a pro in this language so cannot give an example code. Sorry about that.

Populate AngularJS {{expression}} within ng-repeat using a second array

I'm completely rebuilding my website (originally hacked together with Wordpress) using Laravel and AngularJS. It's been a massive learning experience and I think I'm nearly there but for one problem.
On my site 'schemes' (or courses) are made up of 'units' which are made up of 'lessons'. Retrieving this data is fine, using Eloquent I retrieve valid JSON like this made up example...
[
{
"id": "1", //Scheme Id
"title": "Sports",
"description": "This is a Sports course!",
"units": [
{
"id": "1",
"title": "Tennis",
"lessons": [
{
"id": "6",
"title": "Serving"
},
{
"id": "7",
"title": "Hitting the ball with top-spin"
}
]
},
{
"id": "2",
"title": "Athletics",
"lessons": [
{
"id": "1",
"title": "Long Jump"
},
{
"id": "2",
"title": "Hurdling Technique"
}
]
},
{
"id": "4",
"title": "Golf",
"lessons": [
{
"id": "4",
"title": "Pitching"
},
{
"id": "5",
"title": "Putting"
}
]
}
]
}
....
]
Separately I have a simple array of completed lesson ids for a particular user like this...
[2, 6, 8, 9] ///User has completed lessons with ids of 2,6,8 and 9
In my view I'm using nested ng-repeat loops like so...
...
<div ng-controller="SchemesController">
<div ng-repeat="scheme in schemes">
<h1>{{scheme.title}}</h1>
<div ng-repeat="unit in scheme.units">
<h3>{{unit.title}}</h3>
<div ng-repeat="lesson in unit.lessons">
<div>{{lesson.title}}: {{status}}</div>
</div>
</div>
</div>
</div><!--[end of ng-controller="SchemesController"]-->
....
SchemesController (v simple!) looks like this...
var app = angular.module('schemesApp', []);
app.controller('SchemesController', function($scope){
$scope.schemes=jsonData;
});
The problem is I have no idea how to populate the {{status}} field which I want to state simply 'Complete' or 'Incomplete. I investigated whether I could somehow add this info to my original array like this...
"lessons": [
{
"id": "6",
"title": "Serving",
"status": "Complete" //populated somehow
},
{
"id": "7",
"title": "Hitting the ball with top-spin",
}
]
but I got nowhere slowly. Is there a way to do this (I've played around with underscore.js and felt this could help?).
Or do I populate {{status}} from creating and calling a javascript function?!?
ANY help that anyone could offer would be incredible. I'm a school teacher and for some sadistic reason I find a bit of programming/web design a fun use of my spare time so I apologise if this is a stupid question. THANKS in advance!!!
btw if anyone has a better 'title' for this question then please let me know.
I'm assuming you don't need to persist the status back to the database...
This is where you're having the problem:
<div>{{lesson.title}}: {{status}}</div>
You really don't need to store the status in your data model, because it's just used for presentation purposes.
Let's say your array of completed lessons is defined like this:
$scope.completedLessons = [1, 2, 3, 4, 5] // Or however you'd assign it
You need to create a function in your scope like this:
$scope.isLessonCompleted = function(lessonId) {
return $scope.completedLessons.indexOf(lessonId) > -1;
};
Then you need to change the html from above to this:
<div>{{lesson.title}}: {{isLessonCompleted(lesson.id) && 'Complete' || 'Incomplete'}}</div>
If lessons are also a model and each lesson should have a status, which isn't a column/field in your table but is something you'll add logic to determine, you could add a custom model accessor by adding the following to your models/Lesson.php:
// Append custom accessor attributes
protected $appends = ['status'];
public function getStatusAttribute() {
// Add logic here
return 'Complete';
}
This way, when you use Eloquent to retrieve your data, you'll also see a status attribute as part of the object, so you could then access it as usual $lesson->status (PHP) or lesson.status (JS).
For more information, see the official Laravel documentation on accessors and mutators

Categories

Resources