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!
Related
I have a table with a feature to select value of a row to send it to the Flask backend, that on button click also redirects my users to a different endpoint. What I need is to open the new endpoint requested in a new webpage instead of the same page. My HTML code where the button is located is as follows. It envelopes a table column value.
{% for item in rows %}
<tr>
<td>{{ item[0] }}</td>
<td>
**<button** formaction="/stockpopup"
type="submit" name = 'stock' value = {{`item[11] }}>
{{ item[11] }}**</button>**
</td>
<td>{{ item[1] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
I am looking for possible alternates to using JavaScript to achieve this outcome if anyone can help.
You can use the onclick method inside of html.
Something like this should work:
<button onclick="window.open('https://stackoverflow.com','_blank')">Open in new tab</button>
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
I have a web app, front end is Vue.js, backend is Django.
I want to assign every row an name with increment integer to differ the rows in the table, so in the backend I could loop though an integer range to deal with them separately after form submitting.
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form id="myform" method="post" action="/tag_course/">
<table>
<thead>
...
</thead>
<tbody>
<tr v-for="(row, index) in Rows" :key="`isbn-${index}`">
<td :name="`title_${index}`" >{{ row.title }}</td>
<td :name="`discipline_code_course_code_${index}`" bgcolor= "white"><div contenteditable></div></td>
</tr>
</tbody>
</table>
<select id="semester" name="semester">
<option value="test">test</option>
</select>
</form>
</div>
<script>
var book_rows = [{title:1, author:1, edition:1}, {title:2, author:2, edition:2}, {title:3, author:3, edition:3}]
const app = new Vue({
el: '#app',
data:() => ({
filter: '',
rows: book_rows
}),
});
</script>
backend:
def check(request):
if request.method == 'POST':
print(request.POST) #here I only got semester value, but no
title and discipline_code_course_code related value
I have around 1 thousand rows, how could I make name like Title_1, Title_2.... for the name attribute in different rows?
I have tried :name="title_${index}" as the name but failed. Backend no such key in post data
In the backend I could only got the normal name value(semester), but could not get the value using :name="discipline_code_course_code_${index}or:name="title_${index}
Try using the below
<td name="Title_{{index}}">{{ row.title }}</td>
or
<td :name="`Title_${index}`">{{ row.title }}</td>
If I see it right you're already doing what you want to achieve! The combination of Isbn and the index you are using as key is the same you want to have for the name prop.
So you could just use
<td :name="`title_${index}`">{{ row.title }}</td>
By the way, it would be better to use something other than "isbn" and the index as the key. Maybe the real isbn if you have it, since it is unique.
I have a simple Flask application with just one table.
So python code is irrelavantly simple:
#app.route('/')
def home():
items = long_db_request()
return render_template("index.html", items=items)
#app.route('/extended')
def extended():
return render_template("animals.html")
And items is a huge JSON object.
I created a table which reflects that data:
<table>
<tr>
<th style="text-align:center">id</th>
<th style="text-align:center">creation time</th>
<th style="text-align:center">name</th>
<th style="text-align:center">animals</th>
<th style="text-align:center">number</th>
</tr>
{% for item in items %}
<tr>
<td> {{ item.id }} </td>
<td> {{ item.time }} </td>
<td>
{{ item.name }}
</td>
<td> {{item.group}} </td>
<td>{{ item.group|length }}</td>
</tr>
{% endfor %}
</table>
The table looks like:
As you can see, column animal contains a lof of object which makes it all difficult to percieve.
I want it to be like this
which is a lot easier to get. And show animals is a link to another page, where a pure json exists.
How can I achieve this?
I followed the doc of jinja2 and Flask and found method url_for() but in that case I have to pass all my json in query which is unacceptable..
How can I jump from first image to exellent nice view of the second one?
working code with the first picture is place here
Thank you very much in advance!
P.S. I only saw one question here with rellevant topic, but it does not help me
Instead of passing all the animals (e.g. cats) from one view to another, just pass the category cats to the next page.
The view function for the next page then selects all cats from the json, and passes the cats then to the detailed view.
So, on you overview page, you render links like species.html?cats (and so on), and when somebody clicks on these links the view function selects all cats, and then passes them into a render_template("species.html", species=cats) view.
I am trying to save checked off checkboxes.
The issue I am having right now is that when I press the email button, the page goes blank and when I try to go back, it asks me if I want to "Confirm Form Resubmission". I also tried linking the same page back like this in the form tag:
<form action="{% url 'ordered_user_list' %} method="post">
Note that the email button shouldn't do anything except reload the same page, but have the boxes checked as before. Also, if I come back to it from a different page, it should still be checked off as before.
in html file
<form method="post">
<table class="table">
<tr>
<th></th>
<th><u>Last Name</u></th>
<th><u>First Name</u></th>
<th style="width: 30%"><u>Email</u></th>
<th><u>Phone</u></th>
</tr>
{% for user in object_list %}
<tr>
<td><input type="checkbox" name="emailList" value="{{user.id}}"></td>
<td> {{ user.lastName|capfirst }}</td>
<td><a href="{% url "user_info" user.id %}">{{ user.firstName|capfirst }}</td>
<td>{{ user.email }}</td>
<td>{{ user.phone }}</td>
</tr>
{% endfor %}
</table>
{% csrf_token %}
<input class = "btn btn-danger" type="submit" value="Email"/></form>
in View file
class OrderedUserList(ListView):
model = User
template_name = "Schedule/ordered_user_list.html"
def dispatch(self, *args, **kwargs):
if not self.request.user.is_authenticated() or (not self.request.user.admin and not self.request.user.volunteer_coordinator):
return forbidden()
checked = request.POST.get('emailList')
return super(OrderedUserList, self).dispatch(*args, **kwargs)
You can save the selections by setting a COOKIE(in your view) by using the 'set_cookie' command.You can then access this cookie within your session and get the values of selections wherever you want.But remember that 1)the cookie saves your selection as a single string so be careful about how you save your selections so it is easier to extract them later (using string split method) and 2)it has a downside that this will be a system-dependent solution as the cookie wont be accessible if you save a cookie on one device and try to login from some other device/system at the same time.Hope this helps....