how do I access nested json data with vuejs> - json

I would like to create a table and populate it with data using vue.js and v-for but I don`t know how to access the nested JSON file.
If I simply call {{items}} the data is presented but there is no way i manage to filter it
here is my code:
<template>
<div id="app">
<thead>
</thead>
<tbody>
<table>
<thead>
<tr>
<th>id</th>
<th>press</th>
<th>date</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.results.downloadable.document_en }}</td>
<td>{{ item.}}</td>
</tr>
</tbody>
</table>
</tbody>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
items:[]
}
},
created() {
axios.get(`https://zbeta2.mykuwaitnet.net/backend/en/api/v2/media-center/press-release/?page_size=61&type=5`)
.then(response => {
this.items = response.data
})
}
}
</script>

Based on the result of your endpoint you should change your assignment of items to
.then(response => {
this.items = response.data.results
})
And your loop to
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<!-- as downloadable is an array, see update below etc. -->
</tr>
But be aware - if you assign the data.results directly you will lose the so called "paginator" information that also contains the link to load more.
So another option would be to assign
this.items = response.data
HOWEVER, be aware that you should then define items in your data as null or empty object (not array, as this would be false)
And then change your loop to something like this (it's now looping in item.results)
<tbody v-if="items && items.results">
<tr v-for="item in items.results" :key="item.id">
<td>{{ item.id }}</td>
<!-- as downloadable is an array - see Update below etc. -->
</tr>
</tbody>
This approach would allow you to show the total count via items.count for example
UPDATE:
Actually downloadable is an array! I can only assume what you actually want to achieve to here. I've created a jsfiddle to showcase it: https://jsfiddle.net/v73xe4m5/1/
The main thing you probably want to do is filter the entry to only show entries where downloadable contains a document_en.
<tr v-for="item in items.results" :key="item.id">
<td>{{ item.id }}</td>
<td>
<div class="downloads">
<span
v-for="downloadable in item.downloadable.filter(d => !!d.document_en)"
:key="downloadable.id"
>{{ downloadable.document_en.file }}</span>
</div>
</td>
</tr>
I'm not familiar with that endpoint / api - so I don't know if it might return more than one relevant document per item.
As you can see I used a second v-for loop inside the <td> in order to go through all downloadable entries. Before doing so, they are filtered, so only entries that actually have a document_en value are shown. You can adapt this as you want.
Hope that helps!

this is the correct form to get the array from the json and save to this.items
this.items = response.data.results
I encourage you to always console.log(response) after api call , and access data according to the structure of the api results

Related

subscribe display [Object Object], can't make an *ngIf outside of *ngFor

I created an angular Quiz project, every ID can make quizzes and I want to display every Quiz that a logged user has done. I did it like this.
// here I call the user id and the id_category inside Result[], but I can't use it on the html part.
ngOnInit() {
this.supabase.authChanges((_, session) => this.session2 = session);
this.getProfile();
this.supabaseQuiz.getResult().subscribe((res: Result[]) => {
let resultIdAns = res
this.result = resultIdAns
//here I get the result = [Object, Object]
})
//passare category id
this.supabase.profile.then(profile => {
if(profile.data){
this.userProfile = profile.data
}else{
// this.router.navigateByUrl('account/addProfile')
}
})
}
this is the html part:
here I try to if the result.id_category with the userID to display only his quiz but this if inside the for destroy all the table!
<nz-table #headerTable [nzData]="result" [nzPageSize]="50" [nzScroll]="{ y: '240px' }">
<thead>
<tr>
<th>Category</th>
<th>Date</th>
<th>Correct answers</th>
<th>Final score</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let res of result">
<div *ngIf="this.userProfile?.id === res.id_profile">
<td>{{ res.categoryTitle }}</td>
<td>{{ res.date }}</td>
<td>{{ res.rightAnswer }}</td>
<td>{{ res.finalScore }}</td>
<button nz-button nzType="primary" success (click)="goToDetail(parameterValue)">Dettagli</button>
<!--<td>{{ res.json_answer }}</td>-->
</div>
</tr>
</tbody>
</nz-table>
there is way to do another subscribe maybe and get the result id_category outside the for? Thanks
1- You can make the filtering of the ids check in the ts file using array.find() against res.id_profile and userProfile?.id.
2- You do not need to create a new property named resultIdAns since you can assign the API endpoint response to the result property directly.
3- You cannot make the *ngIf="" check outside the *ngFor="" because the condition predicate in the *ngIf="" depends on the variable named res from the outer element which is the container of *ngFor=""
4- Your usage of this. keyword in the template inside the *ngIf="" is invalid.
5- whenever you want to use structural directive it is better for performance reasons to use <ng-container *ngIf="" ></ng-container> or <ng-container *ngFor="" ></ng-container>

Save to Database when someone updates notes field in html table (django)

I have found many answers to this on SO but my understanding of all of this is still too new to be able to understand how to implement so just posting my exact question:
I have a table which is a filtered view of my database that shows up on one page of my app. It has a notes column where each cell uses content-id-editable. I want to add a save button and when someone wishes to save that particular notes section cell I want them to be able to press "save" and have the updated cell post to the database.
UPDATED QUESTION:
I have made an attempt at using AJAX to push the data to the database (based on #rastawolf's answer) but I haven't made much progress and everything online seems to be geared toward inputting an entire form instead of one column of a table. Here's where I'm at so far:
notes.js:
function saveNoteAjax() {
return $.ajax({
type: 'POST',
url: '/Users/justinbenfit/territorymanagerpython/homepage/views.py/notes',
data: {note: document.getElementById('notes').value,}
})
}
async function SaveLoadNote(){
await saveNoteAjax()
return $.ajax({
type: 'GET',
url: '/Users/justinbenfit/territorymanagerpython/homepage/views.py/notes',
data: {note: document.getElementById('notes').value}
})
let location = "/Users/justinbenfit/territorymanagerpython/homepage/", """I don't have any idea how to make the page refresh"""
location.reload()
}
detail.hmtl:
<table class= "content-table">
<thead>
<tr>
<th>Name</th>
<th>Distributor</th>
<th>State</th>
<th>Brand</th>
<th>Cell</th>
<th>Email</th>
<th>Notes</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
{% for tm in territory_manager %}
<td style="white-space:nowrap;">{{ tm.Name }}</td>
<td style="white-space:nowrap;">{{ tm.Distributor }}</td>
<td style="white-space:nowrap;">{{ tm.State }}</td>
<td style="white-space:nowrap;">{{ tm.Brand }}</td>
<td style="white-space:nowrap;">{{ tm.Cell }}</td>
<td style="white-space:nowrap;">{{ tm.Email }}</td>
<td id='notes' contenteditable="True">{{ tm.Notes }}</td>
<td><input type='submit', align="right" value='Update' class='btn btn-primary'></td>
</tr>
{% endfor %}
</tr>
{% else %}
<h2>No Results for: {{ state }} </h2>
{% endif %}
</tbody>
</table>
<!-- Scripts -->
<script src="assets/js/notes.js"></script>
</body>
</html>
views.py:
def notes(request):
if request.is_ajax():
note = request.POST['note']
updatedNote = TM.objects.update(note) #how is the database supposed to know which tm's notes field to update? How do I pass that information in here?
return render(request, 'homepage/detail.html', {"note": updatedNote})
I wouldn't recommend setting it up this way as the page will refresh every time someone saves a note...
Why don't you instead send the POST data via AJAX?
You will need to write a JavaScript function that you can call when your button is clicked.
You can do something simple like...
Notes.js
function saveNoteAjax() {
return $.ajax({
type: 'POST',
url: 'your route to the function notes function in views.py',
data: {note: document.getElementById('yourNotesInput_ID').value}
})
}
async function SaveLoadNote(){
await saveNoteAjax()
*use another Ajax call to get the new notes from the DB*
*insert some function to refresh the notes on-screen*
}
views.py
def notes(request):
if request.is_ajax():
note = request.POST['note']
*insert your code for updating your DB table*
return HttpResponse('')
If you don't want AJAX, you could make your entire table into a Django model formset. Each notes field would be an input element. To get started, {{form.notes}}. Once it's working you can change your html to render the and style the form field any way you want). The other non-editable fields would be accessed with {{form.instance.fieldname}}
The differemce would be that the user would need to explicitly update after making changes, i.e. you need an Update button to submit the change(s)
Formsets and model formsets look complicated to start with, but they aren't really once you have done a few on them!

Is there a way I can incorporate mailto links with ngFor?

I create an Object and use ngFor to loop through it and create a table. I would like to somehow incorporate mailto links if possible.
I have this finalResults object that looks something like this:
[
{key: 'example#example.com', value: 'message'}
]
Where message is something like
"Please contact the Login Team for help."
I would like to make Login Team a mailto link.
I have already tried making the message like this
Please contact the Login Team for help.
But on the webpage it just displayed that exactly. There was no link.
I use ngFor to loop through my object and make a table.
< <tr>
<th *ngFor="let col of displayedColumns">
{{ col }}
</th>
</tr>
<tr *ngFor="let item of finalResults">
<td>{{ item.key }}</td>
<td>{{ item.value }}</td>
</tr>
<tr></tr>
</table>
Is there some way to do this?
If you want to keep your text as html text then consider using innerHTML binding:
ts
finalResults = [
{
key: 'example#example.com',
value: 'Please contact the Login Team for help.'
}
];
html
<td [innerHTML]="item.value"></td>
Ng-run Example
In component declare
email: string = 'mailto:misesasd#gmail.com'
in template:
<a [href]="email">misesasd#gmail.com</a>
array:
<tr *ngFor="let item of finalResults">
<td><a [href]="item.key">{{item.key}}</a></td>
<td>{{ item.value }}</td>
</tr>
or:
<tr *ngFor="let item of finalResults">
<td>{{item.key}}</td>
<td>{{ item.value }}</td>
</tr>
<tr *ngFor="let item of finalResults">
<td>{{ item.value }}</td>
</tr>

Why my Json data is not display in table using angular ng-repeat?

I want to display my Json data that return from PHP file as like this:
"{\"success\":true,\"message\":\"Transaction history found.\",\"user_transactions\":[{\"user_id\":\"4\",\"amount_charged\":\"4.00\",\"amount_transferred\":\"14400.00\",\"app_rate\":\"3600.00\",\"charged_currency\":\"USD\",\"beneficiary_phone\":\"256775542757\",\"beneficiary_first_name\":\"Sapkota\",\"beneficiary_last_name\":\"Suresh\",\"beneficiary_country\":\"UG\",\"transferred_currency\":\"UGX\",\"transaction_status\":\"Delivered\",\"order_id\":\"259\",\"created_date\":\"2017-07-25 13:35:48\",\"last_modified_date\":\"2017-07-25 13:35:48\"},{\"user_id\":\"4\",\"amount_charged\":\"5.00\",\"amount_transferred\":\"18000.00\",\"app_rate\":\"3600.00\",\"charged_currency\":\"USD\",\"beneficiary_phone\":\"256775542757\",\"beneficiary_first_name\":\"Sapkota\",\"beneficiary_last_name\":\"Suresh\",\"beneficiary_country\":\"UG\",\"transferred_currency\":\"UGX\",\"transaction_status\":\"Delivered\",\"order_id\":\"258\",\"created_date\":\"2017-07-25 06:23:05\",\"last_modified_date\":\"2017-07-25 06:23:05\"}]}"
Which is fetch using Get as like:
$http.get("clients.php").then(function (response) {
$scope.response = response;
$scope.results = JSON.parse(response.data);
console.log($scope.results);
}
The problem is that, don't get any result in console .log & nothing in table row which I have write in this way. So, anybody please help me.
<table>
<tr ng-repeat="result in results.user_transactions">
<td>{{ result.beneficiary_first_name}}</td>
<td>{{ result.transaction_status }}</td>
</tr>
</table>
You need to parse the response as it is string.
$http.get("clients.php").then(function (response) {
$scope.response = response;
$scope.results = JSON.parse(response.data);//Parsing string to JSON
console.log($scope.results);
}
<table>
<tr ng-repeat="result in results.user_transaactions">
<td>{{ res.beneficiary_first_name}}</td>//No need of using index of array
<td>{{ res.transaction_status }}</td>
</tr>
</table>
First you have to parse your string result to JSON using JSON.parse().
$scope.results = JSON.parse(response.data);
Also there is another issue in your html
<table>
<tr ng-repeat="result in results.user_transactions">
<td>{{ result.beneficiary_first_name}}</td>
<td>{{ result.transaction_status }}</td>
</tr>
</table>
Working Demo

ng-repeat shows only if DB return more than one result

I'm working on coupons project, and i want to display to the client all the coupons that available to purchase.
When i click on the button that call to the function "getAllCoupons()" it works and it returns the results in JSON, but when i want to Insert the results into the table with ng-repeat it displays only if the function returns more than one coupon, if there is only one coupon the ng-repeat don't displays nothing.
This is my controller
angular.module('companyApp', []);
angular.module('companyApp').controller('companyController',
function($rootScope, $scope, $http) {
$scope.getAllCoupons = function() {
$http.get("rest/CompanyService/getAllCoupon").success(
function(response) {
$scope.allCoupons = response.coupon;
});
This is my HTML
<div ng-app="companyApp" ng-controller="companyController">
<button class="tablinks" ng-click="getAllCoupons()" id="getAll">Get all coupons</button>
<table align="center" class="table table-striped" style="width: 900px;">
<thead>
<tr>
<th> Id </th>
<th>Coupon Title</th>
<th>Amount</th>
<th>Start Date</th>
<th>End Date</th>
<th>Price</th>
<th>Message</th>
<th>Coupon Type</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in allCoupons">
<td>{{ x.id }}</td>
<td>{{ x.title }}</td>
<td>{{ x.amount }}</td>
<td>{{ x.startDate }}</td>
<td>{{ x.endDate }}</td>
<td>{{ x.price }}</td>
<td>{{ x.message }}</td>
<td>{{ x.type }}</td>
</tr>
</tbody>
</table>
</div>
But if i write it without the ng-repeat it works and i get it in JSON:
<div ng-app="companyApp" ng-controller="companyController">
<button class="tablinks" ng-click="getAllCoupons()" id="getAll">Get all coupons</button>
{{ allCoupons }}
</div>
The response for single coupon is:
{"coupon":{"amount":"149","endDate":"04/12/2020","id":"6","message":"only big sizes","price":"79.9","startDate":"07/08/2014","title":"pajamas","type":"FASHION"}}
And the response for multiple coupons is:
{"coupon":[{"amount":"60","endDate":"05/09/2020","id":"5","message":"warranty for 1 year","price":"200.99","startDate":"20/02/2014","title":"sunglasses","type":"FASHION"},{"amount":"149","endDate":"04/12/2020","id":"6","message":"only big sizes","price":"79.9","startDate":"07/08/2014","title":"pajamas","type":"FASHION"}]}
Thanks for help :)
You are referencing an object not an array, check the docs for using an object in ngRepeat's arguments.
You would need ng-repeat="(key, value) in allCoupons
Try this
<tr ng-repeat="(key, value) in allCoupons">
<td>{{ value.id }}</td>
<td>{{ value.title }}</td>
<td>{{ value.amount }}</td>
<td>{{ value.startDate }}</td>
<td>{{ value.endDate }}</td>
<td>{{ value.price }}</td>
<td>{{ value.message }}</td>
<td>{{ value.type }}</td>
</tr>
Hope it helps
The server's response for a single coupon is in a different format from what it is for multiple coupons.
You should talk to your server guys and ask them to fix this. The coupon attribute needs to be an array of coupons regardless of whether there is a single coupon or multiple coupons. If there are no coupons, the coupon variable can either be undefined or an empty array.
If the server guys make this change for you, your UI code should work as is.
I understand, sometimes, it can be hard to get the server guys to comply with your request in a timely fashion, especially if they are on a different team.
If this is the case, you can put in a minor patch on the UI code to get the UI working with the existing service, until the server guys come up with a fix. You will have to change your $http.get snippet like below (Also incorporating the .success to .then change suggested by #Claies):
$http.get('rest/CompanyService/getAllCoupon').then(
function(response) {
if(!response.coupon) {
// No Coupons
$scope.allCoupons = [];
} else if(response.coupon instanceof Array) {
// Multiple Coupons
$scope.allCoupons = response.coupon;
} else {
// Single Coupon
$scope.allCoupons = [response.coupon];
}
});
Note: This fix is only a temporary solution. The server code has to be fixed eventually. There is absolutely no justification for the server to send the response in different formats.