Vue.js For loop is not rendering content - django

I am building a web application using vue.js, vue-resource, vue-mdl and google material design lite.
JS compilation is performed using webpack through laravel elixir.
In this app I have to render a table row for each object from an array returned from a Rest API (Django Rest Framework). I have made the following code inside the html to render content using vue.js:
<tr v-for="customer in customers">
<td class="mdl-data-table__cell--non-numeric">{{ customer.status }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ customer.name }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ customer.company }}</td>
<tr>
This should render all objects in the array as a table row. I have also tried to wrap the above in a template tag like this:
<template v-for="customer in customers">
<tr>
<td class="mdl-data-table__cell--non-numeric">{{ customer.status }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ customer.name }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ customer.company }}</td>
</tr>
</template>
This did not change either.
I have also tried to hardcode the array inside the ready() function of the vue instance, but this did not help either.
window._ = require('lodash');
require('material-design-lite');
window.Vue = require('vue');
require('vue-resource');
var VueMdl = require('vue-mdl');
Vue.use(VueMdl.default);
const app = new Vue({
el:'body',
ready: function(){
//this.getCustomerList();
this.customers = [
{ name: "Peter", status: "true", company: "Company 1"},
{ name: "John", status: "false", company: "Company 2"}
]
},
data: {
customers: [],
response: null,
messages: []
},
methods: {
getCustomerList: function()
{
this.$http({url: '/api/customers/', method: 'GET'}).then(function(response){
//Success
this.customers = response.data
console.log(response.data)
},
function(response){
console.log(response)
})
}
}
})
Changing the above to this does not change either:
window._ = require('lodash');
require('material-design-lite');
window.Vue = require('vue');
require('vue-resource');
var VueMdl = require('vue-mdl');
Vue.use(VueMdl.default);
const app = new Vue({
el:'body',
ready: function(){
//this.getCustomerList();
},
data: {
customers: [
{ name: "Peter", status: "true", company: "Company 1"},
{ name: "John", status: "false", company: "Company 2"}
],
response: null,
messages: []
},
methods: {
getCustomerList: function()
{
this.$http({url: '/api/customers/', method: 'GET'}).then(function(response){
//Success
this.customers = response.data
console.log(response.data)
},
function(response){
console.log(response)
})
}
}
})
I have also tried to just make a plain html table that does not have any of the Google MDL classes applied, and this does also not give any result.
Logging this.customers to the console shows that it does in fact contain the data, but for reason it is not rendering. Why is that? What am I doing wrong?

Here's a snippet of your code, which works as expected. I've added in CDN references to the libraries you mentioned, but I'm not doing anything with them. I offer this as a starting point for you to see if you can find what changes will reproduce your problem here.
const app = new Vue({
el: 'body',
ready: function() {
//this.getCustomerList();
this.customers = [{
name: "Peter",
status: "true",
company: "Company 1"
}, {
name: "John",
status: "false",
company: "Company 2"
}]
},
data: {
customers: [],
response: null,
messages: []
}
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/vue-resource/0.9.3/vue-resource.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.2.0/material.indigo-pink.min.css">
<script defer src="https://code.getmdl.io/1.2.0/material.min.js"></script>
<script src="https://rawgit.com/posva/vue-mdl/develop/dist/vue-mdl.min.js"></script>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--3-col">
<button id="create-customer" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect" #click="$refs.createCustomer.open">
Create customer
</button>
</div>
<div class="mdl-cell mdl-cell--3-col">
<button id="convert-reseller" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Convert to reseller
</button>
</div>
<div class="mdl-cell mdl-cell--3-col">
<button id="remove-customer" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Remove Customer
</button>
</div>
<div class="mdl-cell mdl-cell--3-col">
<button id="change-status" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Change status
</button>
</div>
</div>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--12-col">
<table class="mdl-data-table mdl-js-data-table mdl-data-table--selectable" style="width:100%;">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">Status</th>
<th class="mdl-data-table__cell--non-numeric">Customer name</th>
<th class="mdl-data-table__cell--non-numeric">Company</th>
</tr>
</thead>
<tbody>
<tr v-for="customer in customers">
<td class="mdl-data-table__cell--non-numeric">{{ customer.status }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ customer.name }}</td>
<td class="mdl-data-table__cell--non-numeric">{{ customer.company }}</td>
</tr>
</tbody>
</table>
</div>
</div>

It seems now to be working.
Inside app.js I had:
const app = new Vue({ el: 'body' })
That, for some reason, conflicted with the one I was creating inside customer_list.js—although my methods worked fine.

Related

Variable change doesn't render in the view

The intention of the following code is to display a row if unique identifier of the row above is within the rows array. Why does Svelte update the view only after several clicks, in a seemingly random way?
<script>
import { onMount } from "svelte";
let rows = [
{"name": "Alex", "id": "0"},
{"name": "Steve", "id": "1"},
{"name": "Mike", "id": "2"},
];
let expandedRows = [];
function toggleExpandRows(row_id_to_toggle) {
console.log("Row to toggle:", row_id_to_toggle)
console.log(expandedRows);
if (expandedRows.includes(row_id_to_toggle)) {
console.log(expandedRows, "includes", row_id_to_toggle)
expandedRows = expandedRows.filter(expanded_row_id => expanded_row_id !== row_id_to_toggle)
} else {
expandedRows.push(row_id_to_toggle);
}
}
</script>
<div class="overflow-x-auto w-full">
<table class="table table-compact w-full">
<thead>
<tr>
<th></th>
<th>Name</th>
</tr>
</thead>
<tbody>
{#each rows as row (row.id)}
<tr>
<td>
<button class="btn btn-xs" on:click={()=>toggleExpandRows(row.id)}>+/-</button>
</td>
<td class="min-w-[3rem] ">{row.name}</td>
</tr>
row.id: {JSON.stringify(row.id)}
{#if expandedRows.includes(row.id)}
<tr>
<td colspan="2">-</td>
</tr>
{/if}
{/each}
</tbody>
</table>
Expanded: {JSON.stringify(expandedRows)}
</div>
REPL
Reactivity is based on assignments, which is why for arrays you also often see this pattern instead of push:
array = [...array, item];
Instead of just expandedRows.push(row_id_to_toggle), you should also assign expandedRows, so Svelte will know it has changed.
You can try:
.
.
.
else {
expandedRows.push(row_id_to_toggle);
expandedRows = expandedRows
}

Issues with csfr token and ajax call

I tried to implement a button on a Website, which upon pressing it automatically runs a python function on the server and copies some value into the clipboard of the user. The clipboard copying runs fine, but I can not run the python function.
Whenever I try to I get an error 403 and I think it is due to an issue with the csfr token. Can anyone help me to solve this issue?
Here is my HTML
{% if categories %}
<div class="card shadow mb-4">
<div class="card-body card-interface">
<table id="predictionTable" class="table table-bordered">
<thead>
<tr>
<th>Vorhersage</th>
<th>Wahrscheinlichkeit</th>
<th>Kopieren</th>
</tr>
</thead>
<tbody>
{% for category in categories %}
<tr>
<td>{{ category.0}}</td>
<td>{{ category.1}}%</td>
<td><img src="{% static "documents/img/copy.png" %}" class="interface-copy" value="{{ category.0 }}" input_text = "{{ input_text }}" style="cursor: pointer"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div id="django-data" data-CSRF="{{csrf_token}}"></div>
And here the .js that is run
$(".interface-copy").on('click', function(e) {
var csrftoken = $("django-data").data().CSRF;
console.log(csrftoken);
console.log("test")
var $temp = $("<input>");
$("body").append($temp);
$temp.val($(this).attr('value')).select();
document.execCommand("copy");
$temp.remove();
console.log("test")
$.ajax({
url: "/ajax/postSingleSourceEntry/",
type : 'POST',
beforeSend: function(request){
request.setRequestHeader("X-CSRFToken", csrftoken);
},
data: {
csfrmiddlewaretoken: csrftoken
},
dataType: "json",
success: function (data){
console.log("call created")
},
error : function(response){
console.log(response)
}
})
});
Change:
<div id="django-data" data-CSRF="{{csrf_token}}"></div>
To:
<div id="django-data" data-csrf="{{csrf_token}}"></div>
And:
var csrftoken = $("django-data").data().CSRF;
To:
var csrftoken = $("#django-data").data().csrf; // Note the # before django-data and csrf in small letter.
You might want to read: How to get the data-id attribute?
You can add #csrf_exempt decorator for that ajax function

How do i Fix api data not displaying with vue and axios

I can't seem to load the data information on the html table from the api via using vue and axios
I am adding vue as my frontend to my rest api and i have called the api correctly using axios the problem i am having is there is no data shown but the loop displays the number of lines cos i have 3 entries and the table shows 3 empty spaces but no meaningful data and there's no console error please what ami i doing wrong ?
<div class="body">
<table class="table table-bordered table-striped table-hover dataTable ">
<thead>
<tr>
<th>Article Id </th>
<th>Title</th>
<th>Body</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Article Id </th>
<th>Title</th>
<th>Body</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</tfoot>
<tbody>
<tr v-for="article in articles" :key="article.article_id">
<td>{{ article.article_id }}</td>
<td>{{ article.article_title }}</td>
<td>{{ article.article_body }}</td>
<td><button #click="geArticle(article.article_id)" class="btn btn-round btn-primary">Edit</button></td>
<td><button #click="deleteArticle(article.article_id)" class="btn btn-round btn-danger">Delete</button></td>
<td></td>
</tr>
<script>
new Vue({
el: "#startapp",
data: {
articles: [],
// loading: false,
currentArticle: {},
message: null,
currentArticle: {},
newArticle: {'article_title': null, 'article_body': null}
},
mounted(){
this.getArticles();
},
methods: {
getArticles: function() {
axios({
method: 'get',
url: '/api/article'
}).then((response) => this.articles = response.data)
}
}
});
</script>
The data from the api is supposed to show the article_id, article_title and article_body but i get blank spaces and there is no error
One of the things that is likely to go wrong especially as there are no error messages showing is forgetting to run your json-server package. This should run simultaneously as your development tools.
First run:
npm run json
While the above is still running, open another terminal and run this:
npm run serve

Django - Dynamically create element

I am making a complete admin and invoice app in Django.
For the invoice app, as the user clicks on "Create Sales Invoice" the invoice screen appears.
Now I want the system to dynamically generate new bill as soon as this screen appears, but not saved. As the user starts entering item, I want a new item detail (i.e. each bill has one item detail which has the list of items, its quantity and price).
However, none of them shall be saved unless the user clicks on create bill button.
I need help in how to do this thing, ie create a bill and item detail as the user goes to a create bill, link these two with foreign key, but also have the option to discard them if the user does not end up on clicking "save" button.
Edit 1
My invoicing HTML:
{% extends "base.html" %}
{% block title %}
{% load static from staticfiles %}
<script src="{% static 'bill/script.js' %}"></script>
<link rel="stylesheet" href="{% static 'bill/style.css' %}">
<title>Sales Invoice</title>
{% endblock %}
{% block content%}
<invoice>
<div id="invoice">
<invoiceheader>
<!--
<h1>Invoice</h1>
<address>
<p>Jonathan Neal</p>
<p>101 E. Chapman Ave<br>Orange, CA 92866</p>
<p>(800) 555-1234</p>
</address>
<span><img alt="" src="logo.png"><input type="file" accept="image/*"></span>
-->
</invoiceheader>
<invoicearticle>
<!--<h1>Recipient</h1>-->
<code>
<p>Customer code:
<input id="customer-code" ></input></p>
</code>
<address>
<p></p>
<p id="companyname">Some Company</p>
<p id = "companyaddress">c/o Some Guy</p>
</address>
<table class="meta">
<tr>
<th><span>Invoice #</span></th>
<td><span>101138</span></td>
</tr>
<tr>
<th><span>Date</span></th>
<td><span></span></td>
</tr>
<tr>
<th><span>Amount Due</span></th>
<td><span id="prefix">Rs. </span><span>600.00</span></td>
</tr>
</table>
<table class="inventory" id="inventory_table">
<thead>
<tr>
<th colspan="1"><span>Item Code</span></th>
<th colspan="2"><span>Item Name</span></th>
<th colspan="1"><span>Unit Rate</span></th>
<th colspan="1"><span>Discount 1</span></th>
<th colspan="1"><span>Quantity</span></th>
<th colspan="1"><span>Discount 2</span></th>
<th colspan="1"><span>Free Quantity</span></th>
<th colspan="1"><span>VAT Type</span></th>
<th colspan="1"><span>VAT</span></th>
<th colspan="1"><span>Net Rate</span></th>
</tr>
</thead>
<form>
<tbody>
<tr>
<td colspan="1"><a class="cut">-</a><span class="itemcode" contenteditable></span></td>
<td colspan="2"><span contenteditable></span></td>
<td colspan="1"><span contenteditable>150.00</span></td>
<td colspan="1"><span contenteditable></span></td>
<td colspan="1"><span contenteditable>4</span></td>
<td colspan="1"><span contenteditable></span></td>
<td colspan="1"><span contenteditable></span></td>
<td colspan="1"><span contenteditable></span></td>
<td colspan="1"><span contenteditable></span></td>
<td colspan="1"><span contenteditable></span></td>
</tr>
</tbody>
</form>
</table>
<a class="add">+</a>
<table class="balance">
<tr>
<th><span>Total</span></th>
<td><span data-prefix></span><span>600.00</span></td>
</tr>
<tr>
<th><span>Amount Paid</span></th>
<td><span data-prefix></span><span>0.00</span></td>
</tr>
<tr>
<th><span>Balance Due</span></th>
<td><span data-prefix></span><span>600.00</span></td>
</tr>
</table>
</article>
</div>
</invoice>
<script type="text/javascript">
/* url_sellbill = '{% url "billbrain:sellbill" %}' */
csrf_token='{{csrf_token}}'
</script>
{% endblock %}
My related jquery file (only the necessary part):
Generating Table:
function generateTableRow() {
var emptyColumn = document.createElement('tr');
emptyColumn.innerHTML = '<td><a class="cut">-</a><span class="itemcode" contenteditable></span></td>' +
'<td colspan="2"><span contenteditable></span></td>' +
'<td><span contenteditable>100.00</span></td>' +
'<td><span contenteditable></span></td>' +
'<td><span contenteditable></span></td>'+
'<td><span contenteditable></span></td>' +
'<td><span contenteditable></span></td>'+
'<td><span contenteditable></span></td>' +
'<td><span contenteditable></span></td>' +
'<td><span contenteditable></span></td>' ;
return emptyColumn;
}
Adding customer details on user entering customer code:
$( "#customer-code" ).change(function() {
/*alert( "Handler for .change() called." );*/
var input = $("#customer-code").val();
(function() {
$.ajax({
url : "",
type : "POST",
data : { customer_code: input,
datatype: 'customer',
'csrfmiddlewaretoken': csrf_token}, // data sent with the post request
dataType: 'json',
// handle a successful response
success : function(jsondata) {
$('#companyname').html(jsondata['name'])
$('#companyaddress').html(jsondata['address'])
console.log(jsondata); // log the returned json to the console
console.log("success"); // another sanity check
},
});
}());
});
Similarly, for products, on user entering product id, the other details are auto-generated:
$("#inventory_table").on("focus", ".itemcode", function(){
$(this).data("initialText", $(this).html());
/*alert( "On focus for table inventory called." );*/
});
$("#inventory_table").on("blur", ".itemcode", function(){
/*alert( "On blur for table inventory called." );*/
var input = $(this).html();
if ($(this).data("initialText") !== $(this).html()) {
var el = this;
/*valueis='Hi 5'
alert($(this).closest('tr').find('td:nth-child(4) span').html());*/
(function() {
$.ajax({
url : "",
type : "POST",
data : { item_code: input,
datatype: 'item',
'csrfmiddlewaretoken': csrf_token}, // data sent with the post request
dataType: 'json',
// handle a successful response
success : function(jsondata) {
$(el).closest('tr').find('td:nth-child(2) span').html(jsondata['name'])
$(el).closest('tr').find('td:nth-child(2) span').html(jsondata['name'])
$(el).closest('tr').find('td:nth-child(3) span').html(jsondata['sellingprice'])
console.log(jsondata); // log the returned json to the console
alert(jsondata['name']);
console.log("success"); // another sanity check
},
});
}());
}
});
Finally, this is my views.py file's relevant function:
def bill(request):
if request.method == 'POST':
datatype = request.POST.get('datatype')
if (datatype == 'customer'):
customerkey = request.POST.get('customer_code')
response_data = {}
response_data['name'] = Customer.object.get(customer_key__iexact=customerkey).name
response_data['address'] = Customer.object.get(customer_key__iexact=customerkey).address
jsondata = json.dumps(response_data)
return HttpResponse(jsondata)
if (datatype == 'item'):
productkey = request.POST.get('item_code')
response_data = {}
response_data['name'] = Product.object.get(prodkey__iexact=productkey).name
response_data['sellingprice'] = float(Product.object.get(prodkey__iexact=productkey).selling_price)
#response_data['address'] = Product.object.get(prodkey__iexact=productkey).address
jsondata = json.dumps(response_data)
return HttpResponse(jsondata)
return render(request, 'bill/invoicing.html')
You should use Model Forms to output to the user a form to fill and create an object after submit. You can also use some context data if you need to pre-fill some informations in the form.
Another way is to just create an object and flag it as "CANCELLED" if you want to remember some user's tries (what can be useful sometimes) or just remove it (what can cause performance issues if it is very common situation to not fill started bill).

Re-execute model hook and rerender in Ember js

I have in my Ember App, a route displaying a list of offers;
the model is loaded by jquery ajax (I don't use Ember-data):
Ember.$.ajax({
type: 'GET',
url: App.restAPIpath + '/offers/',
headers: {
"tokens": localStorage.tokens
},
async: false
}).then(function(res) {
data = res.offers;
});
return data;
The offers are shown in the template using a datatable and in each row there's a delete button that sends an ajax delete request to the server and correctly deletes the right offer:
{{#view App.dataTableView}}
<thead>
<tr>
<th>Created</th>
<th>Name</th>
<th>Deadline</th>
<th>Duration</th>
<th>Delete?</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Created</th>
<th>Name</th>
<th>Deadline</th>
<th>Duration</th>
<th>Delete?</th>
</tr>
</tfoot>
<tbody>
{{#each offer in model}}
<tr>
<td>
{{offer.createdAt}}
</td>
<td>
{{#link-to 'eng.offers.edit' offer}}{{offer.name}}{{/link-to}}
</td>
<td>
{{offer.deadline}}
</td>
<td>
{{offer.optionDuration}}
</td>
<td>
<button class="form-button-red" {{action "deleteOffer" offer}}>Delete</button>
</td>
</tr>
{{/each}}
</tbody>
{{/view}}
but then I need to update the model (and refresh the view?) because if not the deleted offer is still shown until you refresh the page...
I'd recommend switching your ajax to async, you'll block the router from doing other important things. You should be able to accomplish the same results doing this:
return Ember.$.ajax({
type: 'GET',
url: App.restAPIpath + '/offers/',
headers: {
"tokens": localStorage.tokens
},
}).then(function(res) {
return res.offers;
});
Then I'd do something like this for your delete (I'm going to guess a bit of your code) in your controller's delete action:
actions:{
delete: function(item){
var self = this;
Ember.$.ajax({
type: 'DELETE',
url: App.restAPIpath + '/delete/' + item.get('id'),
headers: {
"tokens": localStorage.tokens
},
}).then(function(){
//manually remove the item from your collection
self.removeObject(item);
});
}
}
BTW I think delete is a reserved key word and jslint and some minimizers are total haters, so you might do something like deleteItem