Vue.js - Displaying JSON results not working correctly - javascript

Before I start this question I am 100% new to vue.js so I may be missing something simple. I've looked through the documentation endlessly and still haven't got a soloution to my problem.
I'm just building a very simple example as practice, where I fill a form and it saves to my DB, but also loads the records I've saved automatically.
This is where it gets strange, when I plug into https://jsonplaceholder.typicode.com/users the JSON data displays correctly in my app.
When I pug into my own backend code, valid JSON is returned but it doesn't display correctly.
This is where I call my Data:
created: function(){
this.$http.get('https://jsonplaceholder.typicode.com/users') // JSON service that is working
this.$http.get('http://localhost:8888/vue_testing/users/get/') // My JSON Service that isn't
.then(function(response){
console.log(response.data);
this.users = response.data;
});
}
Note I am getting back valid JSON from both services.
My valid JSON: http://take.ms/lIa3u
But displays like this: http://take.ms/6dOEL
jsonplaceholder Valid JSON: http://take.ms/VCwKZ
And displays like this:http://take.ms/Ne3fw
This is my complete component code:
<template>
<div class="users">
<h1>Users</h1>
<form v-on:submit="add_user">
<input type="text" v-model="new_user.name" placeholder="Enter name" /><br />
<input type="text" v-model="new_user.email" placeholder="Enter email" />
<input type="submit" value="submit">
</form>
<ul>
<li v-for="user in users">
{{user.name}}: {{user.email}}
</li>
</ul>
</div>
</template>
<script>
export default{
name: 'users',
//Props can accept values from outside the component
data(){
return{
new_user: {},
users: []
}
},
methods:{
add_user: function(e){
//console.log('Add');
this.$http.post('http://localhost:8888/vue_testing/users/set/', this.new_user)
.then(response => {
console.log(response);
}, error => {
console.log(error);
});
e.preventDefault();
}
},
created: function(){
//this.$http.get('https://jsonplaceholder.typicode.com/users')
this.$http.get('http://localhost:8888/vue_testing/users/get/')
.then(function(response){
console.log(response.data);
this.users = response.data;
});
}
}
</script>
<style scoped>
</style>
Again I'm totally new to vue.js, any help in solving this is appricieated. Thanks.

While jsonplaceholder is sending you an array of objects:
[
{
"id": 1,
"name": "Leanne Grehem",
...
}
]
You are sending from your backend an object which holds first the columns, and second a two dimensional array for the data:
{
"COLUMNS": ["ID", "NAME", ...],
"DATA": [
[1, "Leanne Grehem, ...],
[2, "John Doe, ...],
]
}
I would advise you to change your backend so your response looks like that of the jsonplaceholder. Otherwise you would have to make objects out of arrays. Like below:
created: function(){
//this.$http.get('https://jsonplaceholder.typicode.com/users')
this.$http.get('http://localhost:8888/vue_testing/users/get/')
.then(function(response){
console.log(response.data);
let users = [];
const responseData = response.data['DATA']; // Get DATA key from your response
for (user of responseData) { // iterate
users.push( { id: user[0], name: user[1] } ); // create object out of array
}
this.users = users;
});
}
Edit: typo

Related

VueJS and nested v-for: How to get endpoint data through each loop?

I am using VUEJS to build a single page application. I have a single file component that gets some data from an API (using Axios) and uses v-for to render out a list like so:
<template>
<div>
<ul>
<li v-for="division in divisions" :key="division.id_PK">
{{ division.c6code }} - XXX
</li>
</ul>
</div>
</template>
props: {
country: {
type: Object,
required: true
}
},
data() {
return {
divisions: [],
},
methods: {
async getDivisions() {
const divisions = await APIService.getDivisions(
this.country.igpeSID_FK
)
this.divisions = divisions
},
}
An example of the API data source looks like /getDivisions/800001:
{
"status": 200,
"data": [
{
"id_PK": 205891,
"igpeSID_FK": 800001,
"c6code": "AB-CDE"
},
{
"id_PK": 205890,
"igpeSID_FK": 800001,
"c6code": "FG-HIJ"
},
{
"id_PK": 205889,
"igpeSID_FK": 800001,
"c6code": "KL-MNO"
},
{
"id_PK": 205888,
"igpeSID_FK": 800001,
"c6code": "PQ-RST"
},
{
"id_PK": 205887,
"igpeSID_FK": 800001,
"c6code": "WX-YZA"
}
]
}
The rendered UI looks like so:
Now, there is another API endpoint that contains additional data that I need to put in place of the "XXX" placeholder shown above. That additional data source has a property called name and contains the actual division name which was not included in the /getDivisions API (only the associated property id_PK is provided).
Question: How can I get this name for each division?
An example of this endpoint that contains the additional data is: /getDivisionNameById/{id_PK} where id_PK is the parameter I need to pass to it from the getDivisions data shown above. So, for example, if I pass 205891 to the /getDivisionNameById/205891 I get back data that looks like so:
Example /getDivisionNamesById/205891:
{
"status": 200,
"data": [
{
"P_uniqueID": 16919,
"isoGeoDivisionEntry_FK": 205891,
"name": "ZABUL",
"lang": "fa"
},
{
"P_uniqueID": 16918,
"isoGeoDivisionEntry_FK": 205891,
"name": "ZABUL",
"lang": "ps"
}
]
}
I am thinking that I need to create a function that somehow creates a new array of names that I could then loop through in yet another v-for in my original template like so:
<li v-for="division in divisions" :key="division.id_PK">
{{ division.c6code }} - <span v-for="divName in divisionNames" :key="division.id_PK">{{divName.name}}</span>
</li>
async getDivisionNameById(id_PK) {
const name = await APIService.getDivisionNameById(id_PK)
this.divNames.push(name)
}
Obviously, I don't know what I am doing there...
Codesandbox with data:
https://codesandbox.io/s/intelligent-wind-21w35?file=/src/getDivisionNamesById.json
You have to query the data first before rendering the content.
You could fetch all the data in onMounted hook.
Thats a good place for a computed property.
Edit this example as needed depending on how you call your APIs.
You could call both API endpoints in the mounted lifecycle-hook of the component. Included this with a simple timeout to simulate the data coming in at different times.
About the secondary API call(s) where you get the name-data: As you've already said, loop through the IDs and make the API calls. In this case you'd need to wait for the result of your first API call and then use those ID's it returns to make the second API call(s). Maybe this will help you with the await/asyc/then stuff:
How to use async/await in Vue.js?
<template>
<div class="hello">
<ul>
<li v-for="(division, index) in fullList" :key="index">
{{ division }}
</li>
</ul>
</div>
</template>
<script>
import divisions from "#/getDivisionsEntries.json";
import divisionNames from "#/getDivisionNamesById.json";
export default {
name: "DivisionsList",
data() {
return {
divisions: divisions.data,
divisionNames: null,
};
},
mounted() {
setTimeout(() => {
this.divisions = divisions.data;
}, 1000);
setTimeout(() => {
this.divisionNames = divisionNames.data;
}, 3000);
},
computed: {
fullList: function () {
let combinedArr = [];
for (var divi of this.divisions) {
var divNameData = this.divisionNames?.find(
(x) => x.isoGeoDivisionEntry_FK === divi.id_PK
);
if (divNameData !== undefined) {
combinedArr.push(`${divi.c6code} - ${divNameData.name}`);
}
}
return combinedArr;
},
},
};
</script>

Data value not showing up from JSON file at html page after submitting form

Hi everyone out there I require some assistance about Axios & VUE after submitting a form in my webpage i was redirected back to this page. Before the form was submitted the "purposeofvisit" was not empty at the html file but after submitting the form and redirected back to the html page It is empty. I am trying to access the nested object "purposeofvisit" value
let patients = new Vue({
el: "#patients",
data: {
patients: [],
},
mounted: function () {
axios
.get("http://localhost:3000/patients")
.then((response) => {
userParticulars = response.data;
this.patients = userParticulars;
console.log(this.purposeofvisit);
})
.catch((error) => {
console.log(error);
});
},
});
<tbody v-for="(user, index) in patients" :key="index">
<tr>
<td>{{user.appointments[0].purposeofvisit}}</td>
</tr>
</tbody>
This is the JSON file i am accessing
{
"patients": [
{
"id": 1,
"name": "John",
],
"appointments": [
{
"purposeofvisit": "Consultation",
}
]
}
Thee appointments has nested arrays. You could try accessing nested arrays.
user.appointments[0][0].purposeofvisit

Outputting JSON Data in Angular Expressions

My PHP script returns this JSON data:
{
"userData": {
"userName": "knows_nothing",
"userFullName": "Jon Snow",
"userMoney": "124.01"
}
}
How can I access the variables (userName etc) in my webpage?
eg:
JS
var app = angular.module('dashboard', []);
app.controller('userDataCtrl', function($scope, $http) {
data = "{query:'userData'}"
$.post("api/mysql.php", {query:'userData'})
.then(function (response) {$scope.userData = response.userData;});
});
HTML
<div ng-app="dashboard">
<div ng-controller="userDataCtrl">
<h1> Username: {{ userData.userName }} </h1>
<p> Balance: {{ userData.balance }} </p>
</div>
</div>
This has been driving me insane for hours :(
This is what it outputs when I `console.log(response.userData)
Object { userName: "knows_nothing", userFullName: "Jon Snow", userMoney: "124.01" }
According to $http documentation you should read the response from response.data. So, in your case:
...
.then(function (response) {$scope.userData = response.data.userData;});
should do the trick.
Maybe you have to declare the $scope.userData variable outside of the then-function
check if your response is array, if array then you need to do something like this,
$scope.userData = response[0].userData.
If still not getting solution please share or response format.Entire response structure.

Adding to document array in Mongo from Angular Controller

I am having an issue inserting a new JSON object into an array of JSON objects in MongoDB from my Angular Controller.
A simple concept of what I am trying to do is for this schema:
var ThingSchema = new mongoose.Schema({
id: Number,
items: [{
item_id: Number,
item_name: String,
item_price: Number
}]
});
And to add it to my mongodb in a the Mongo console I can use:
db.things.update(
{ "_id": ObjectId("579b7860b168c80c1fe8a32a")},
{ $push: {
"items": {
"item_id" : 134,
"item_name" : "sampleItem",
"item_price" : 234.00
}}
})
However, I'm not sure how I can translate that over to an http request from AngularJS. I used Yeoman to scaffold my app and am more interested in getting a functional prototype right now. In my Angular Controller, I am using this function
addNewItem(thing, newItem) {
this.$http.put('/api/things/' + thing._id, { 'items': newItem})
// on success clear the fields
.then( response => {
console.log(response);
alert(this.newItem);
thing.items.push(newItem);
newItem = {};
});
}
When I call this function I add it to my array that I have instantiated, but I cannot access the actual MongoDB even though a 200 response code is returned.
And in my HTML file I have
<form novalidate class="condition-form">
<fieldset>
<input type="number" ng-model="newItem.item_id" name="" placeholder="Enter item id">
<input type="text" ng-model="newItem.item_name" name="" placeholder="Enter item name">
<input type="number" ng-model="newItem.item_price" name="" placeholder="Enter item price">
<input type="submit" ng-click="$ctrl.addNewItem(thing, newItem)" value="Add">
</fieldset>
</form>
I'm really at a loss for how I can translate this mongodb call to my MEAN stack application. If it helps I am using Babel with EMCAScript 6. Any help means a lot!
Thanks
At the backend of it,when the control reaches the things function in API there you will have to use a mongoDB driver(like Mongodb,Mongoose) for interaction with mongo shell. The save function if you are using mongoose will look something like this:
Things.update({'id':req.params.thing._id},{ $push : {items : req.body.items }},function (err,updated) {
if(err){
console.log(err);
} else {
output = {'msg':'Updated Successfully'};
}
return res.json(output);
});

AngularJS Nested Object Array Pathway

I have a factory, which goes into a controller, and I am trying to get data from that display on an HTML page. I am having trouble specifying an Object's pathway however.
My Factory:
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
apis:
[{
accounts: [
{
v1: [
{
uri: Head+"/v1/accounts/",
item1: "AccountNumber",
item2: "MoneyInAccount"
}],
v2: [
{
uri: Head+"/v2/accounts/",
item1: "AccountNumber",
item2: "MoneyInAccount"
}]
}
],
customers: [
{
v1: [
{
uri: Head+"/v1/customers/",
item1: "CustomerName",
item2: "CustomerID",
item3: "CustomerEmail"
}]
}
]
}]
};
});
My Controller:
app.controller('APIController', function($scope, APIMethodService) {
$scope.title = "API";
$scope.apiList = APIMethodService;
$scope.accountList = $scope.apiList.accounts.v1;
$scope.accountList2 = $scope.apiList[0][0];
});
My HTML
<div ng-controller="APIController">
<div id="api" class="row">
<div class="col-xs-12">
<div class="row" style="font-size:20px">
{{title}} Page!
<table class="table table-striped">
<tr ng-repeat="api in apiList | orderBy:'uri' | filter:search">
<td>{{api.uri}}</td>
<td>{{api.item1}}</td>
<td>{{api.item2}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
The errors I get are in regards to the Controller trying to parse out the individual objects I wish to grab, like accounts or customers, and then any version v#, they may have.
So it will say something such as
TypeError: Cannot read property 'v1' of undefined
I just need some help specifying the proper pathways into my factory service.
You have a few problems. First, you are referring to the object returned from the factory incorrectly. APIMethodService is the factory that you're injecting, so you need to first reference the object that that factory is returning like this:
APIMethodService.apis
This will give you your entire JSON object.
From there, the rest of your object is made up of arrays of objects, so referring to 'v1' won't do you any good. You need to specify an index instead. If you want v1, you'll need:
APIMethodService.apis[0].accounts[0].v1
This will give you the v1 array, which again is an array of objects.
Customers would be:
APIMethodService.apis[0].customers[0].v1
The first problem you have is that the factory returns an object with a single property called apis. So basically this $scope.apiList.accounts.v1 should be $scope.apiList.apis.accounts.v1. Bu that's not all as this won't either work since dotting(.) into apis is an array you'd have to use the index. In this case it would be $scope.apiList.apis[0] and then you could .accounts[0].v1 which is also an array containing a single object.
Now if you can I would suggest to you that you'd change how you represent this data structure.
This is how you could do it.
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
accounts: {
v1: {
uri: Head+"/v1/accounts/",
items: ["AccountNumber","MoneyInAccount"]
},
v2: {
... // skipped for brevity
}
},
customer: {
... // code skipped for brevity
}
};
});
And then it's just a matter of dotting into your APIMethodService-object like APIMethodService.accounts.v1.items[0] if you want the AccountNumber method name.
Constructing your url could then be done like this.
var baseUrl = APIMethodService.accounts.v1.uri; // 'api.example.com'
var url = baseUrl + APIMethodService.accounts.v1.items[0]; // 'AccountNumber'
// url = "api.example.com/v1/accounts/AccountNumber"
Again, this is one way you could do it but this can be further enhanced upon. The examples I provided are simply for demo purposes and this is not in any way the only way to do it.
Expanding upon recieved comments/questions your service (and data representation) could now look like this.
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
accounts: {
v1: {
uri: Head+"/v1/accounts/",
items: [
{
name:'AccountNumber',
description:'Show the account number'
},
{
name:'AccountOwner',
description:'Show information about the owner of the account'
},
{
name:'MoneyInAccount',
description:'Show money in the Account'
}
]
},
v2: {
... // skipped for brevity
}
},
customer: {
... // code skipped for brevity
}
};
});
// Get descriptions
var accountNumberDescription = APIMethodService.accounts.v1.items[0].description; // 'Show the account number'
var accountOwnerDescription = APIMethodService.accounts.v1.items[1].description; // 'Show information about the owner of the account'
var moneyInAccountDescription = APIMethodService.accounts.v1.items[2].description; // 'Show money in the Account'
By using objects with properties like this it's alot easier to understand what you are trying to do. With arrays with indexes you'd have to know or take a look at the source to see what's going on. Here, someone viewing your code they can instantly understand that it is the description you are getting.

Categories

Resources