How i get views.py variable to js file? - javascript

views.py
def somefunction(request):
var = True
return render(request, dasboard.html)
myfirst.js
function myFunction() {
}
How I get var from views.py into the myfirst.js function?

It isn't possible to give a 100% correct answer without knowing the templating engine you are using (DTL, Jinja2?). However, if var doesn't contain any sensitive/private data, the general solution is to pass var to your html template through the context parameter of the render function:
# views.py
views.py
def somefunction(request):
var = True
context = { "var": var }
return render(request, dasboard.html, context)
Then, expose var as a data-* attribute on a html element in your template (the exact implementation will change based on the templating engine you are using):
<!-- dashboard.html -->
<div id="info" data-var="{{ var }}" >
...
</div>
Finally, in your javascript file, you simply retrieve the same html element and access var through the special dataset property:
// myfirst.js
function myFunction() {
var infoElement = document.getElementById("info");
var varValue = infoElement.dataset.var;
}

Related

Pass Django list as argument to Javascript

I have a list passed through the context into the html page of a Django project which I want to read inside of a .js which contains chartjs code. The problem is that .js is reading as string and not as a list/array.
views.py
def index(request):
context = {
"data": [1, 2, 3, 4, 5]}
return render(request, 'index.html', context)
Then, in the html page I have to pass the {{ data|safe }} to a javascript like so:
<script src='{% static "js/chart.js/linechart.js" %}'
var label = "fakelabel";
var index = {{ data|safe }};
></script>
Inside the .js I'm reading the 'index' input as:
document.currentScript.getAttribute("index")
How can I fix this? ('label' is read correctly as str indeed).
{{ data|safe }} is not a safe way to output a Python object as JavaScript.
Use json_script if you want to be safe
This is how to do it.
Write your object as json:
data = {'numbers':['1', '2', '3', '4', '5']}
def index(request):
context = {"data": data}
return render(request, 'index.html', context)
<script>
var index = {{ data|json_script:'mydata' }};
<script>
Then you can use the index variable into another scrip like this:
<script>
const data = JSON.parse(document.getElementById('mydata').textContent);
mydata = data['numbers'];
</script>
You could (and probably should) point to an external JavaScript file rather than using embedded JavaScript.
read here for more details
You can use ajax to fetch list or dict data from views and you need to add jQuery cdn in html file.
from django.http import JsonResponse
def indexAjax(request):
context={"data":[1,2,3,4,5]}
return JsonResponse(context,safe=False)
Inside your js file or script tag
function fun(){
$.ajax({
url:"{% url'indexAjax" %},
dataType:'json',
type:'GET',
success:function(res){
console.log(res.data)
//here you can write your chartjs
}
})}
The correct way to fix the above problem is:
views.py
def index(request):
context ={"data": [1, 2, 3, 4, 5]}
return render(request, 'index.html', context)
charts.html
Then, in the html script you should add {{ data|json_script:"index" }} like you you do with the 'static' tag. Then, always in your .html script you do not need to pass the 'index' list. Therefore when you call the javascript inside your .html you just need to pass:
{{ data|json_script:"index" }}
<script src='{% static "js/chart.js/linechart.js" %}'
var label = "fakelabel";
></script>
js/chart.js/linechart.js
Finally, inside you separate javascript (in this case "js/chart.js/linechart.js"), we can fetch the list with:
JSON.parse(document.getElementById('index').textContent)

How to modify Django template variable with JS and return it changes on it

I would like to pass a list of ids to a view when i click on a link:
<a href="{% url 'app:manage_ids' %}?ids={{ids}}">
So i have created a template var and pass it to js:
{% with ids="" %}
<script type="text/javascript">
window.ids = "{{ ids }}";
</script>
{% endwith %}
I manage object ids when click on checkbox:
<input type="checkbox" class="checkbox" value="{{ object.id }}">
Adding or removing it to a list:
$('.checkbox').change(function() {
var id = $(this).val();
// if django template var is empty
var list_ids = [];
// else
var list_ids = window.ids;
if ($(this).is(':checked')) {
list_ids.push(id);
// here i have to save it on a django template var to use it on the click link
}
else {
const index = list_ids.indexOf(id);
if (index > -1) {
list_ids.splice(index, 1);
// here i have to save it on a django template var to use it on the click link
}
}
});
Anybody could help me about how to do it ?
Thanks you so much.
You cant update the django variable and expect it to update your href value of the link.
Moreover, you should not send the value of a GET query parameter as a list datastructure, instead you'll send it as ?ids=<value1>&ids=<value2>
To do this you'll have to first construct such string of url and then dynamically update the href of your hyperlink with it.
You can first decalre the string variable for you href in javascript somehwere as:
var id_link = "{% url 'app:manage_ids' %}?ids=";
Then whenever the click checkbox function is called you can add new value to this and update the href of link:
id_link += "&ids=" + id;
Add an id to your href and get it and update it
var a = document.getElementById('yourlinkId');
a.href = id_link
Now when someone clicks this link, you can get these in query parmeters in view as:
request.GET.getlist('ids')
and you shall get list of all IDs.
Note (My two cents): Ideally in a good archiecture this should happen by clicking a button with a post request from template in django.

How to pass a django model to a javascript function

I have a javascript function that needs some variables (about 10) from my view. I don't need to call again the variables once the page is loaded. I could give them using a context dict, like below, but maybe is possible to do better.
My models.py:
class Mymodel(models.Model):
my_field1 = #
my_field2 = #
...
my_field10 = #
My views.py:
def myview(request):
context_dict={}
context_dict['myfield1'] = Mymodel.objects.get(id=1).myfield1
context_dict['myfield2'] = Mymodel.objects.get(id=1).myfield2
context_dict['myfield10'] = Mymodel.objects.get(id=1).myfield10
My template.html:
...
<script>
<!--
window.onpageshow = function() {
my_function( '{{ myfield1 }}', '{{ myfield2 }}', ..., '{{ myfield10 }}' );
};
-->
</script>
...
My javascript.js:
function my_function(myfield1, myfield2, ..., myfield10) {
//code
}
These variables are the fields of a model, so i just need to pass the model istance. How can I do that? It's some time I work on it and I think I should use serialize but I don't understand how...
My template.html:
...
<script>
<!--
window.onpageshow = function() {
my_function( serializers.serialize("json", {{ mymodelistance }} ));
};
-->
</script>
...
Thanks in advance
To access your model fields you can directly use angular js ($http.get) method and assign it to the script's variable as per your needs. But for this you would have to make use of Django Tastypie which will allow you to serialize the data which will be then accessible.
This answer is valid if and only if you don't want to do processing on the data in view.
Even if you would like to process the data before saving you can use tastypie hydration.
So here my solution:
My views.py:
def myview(request):
context_dict={}
mymodelistance = Mymodel.objects.filter(id=1)
mymodelistance_json = serializers.serialize('json', mymodelistance)
context_dict['mymodelistance'] = mymodelistance_json
My template.html:
...
<script>
window.onpageshow = function() {
my_function( '{{ mymodelistance|safe }}' );
};
</script>
...
My javascript.js:
function my_function(mymodelistance) {
var mymodelistance_obj = JSON.parse(flag)
var myfield1 = mymodelistance_obj[0].fields.myfield1;
var myfield2 = mymodelistance_obj[0].fields.myfield2;
...
//code
}

Get Django Item ID In Ajax URL

I have a select box in an item edit page, which i would like to be populated via an Ajax call with the saved values.
<script type="text/javascript">
$(document).ready(function() {
$('#editPrefabLineclassBox').on('change', function() {
var selected = this.value;
$.ajax({
url: '/edit-prefab/,
type: 'POST',
data: {
csrfmiddlewaretoken: '{{ csrf_token }}',
lineclassSelected: selected
},
success: function(data) {
var name, select, option;
select = document.getElementById('editPrefabNameBox');
select.options.length = 0;
for (name in data) {
if (data.hasOwnProperty(name)) {
select.options.add(new Option(data[name], name));
}
}
}
});
});
})
</script>
The url i am using in the call is /edit-prefab/. The problem i am having is, the url of the page in Django is actually /edit-prefab/{{ material_item.id }}, only i am not sure how to pass this id to javascript to use in the Ajax call. With just the /edit-prefab/, the page is not found.
After populating the select with the list of items, i would like to have preselected the saved values of the item being edited. I am sure i could populate everything as needed. Its just the setting up of the url that has me a little confused
I have tried passing the id of the item through the view to the template with JSON.dumps, and then parse the variable in JS to use in the url, but i keep getting an unexpected column error when parsing, as from what i know only a dict can be parsed correctly with JSON.
Is there anyone who could please help with this?
EDIT:
def editprefabitem(request, materialitem_id):
context = dict()
mat_item = MaterialItem.objects.get(id=materialitem_id)
context['itemid'] = json.dumps(mat_item.id)
context['lineclass'] = json.dumps(mat_item.lineclass)
context['itemname'] = json.dumps(mat_item.name)
context['diameter'] = json.dumps(mat_item.diameter)
context['quantity'] = json.dumps(mat_item.quantity)
if request.method == 'POST':
if 'lineclassSelected' in request.POST:
lclass = Lineclass.objects.filter(lineclassname=request.POST['lineclassSelected'])\
.values_list('itemname', flat=True).distinct()
request.session['lineclassselected'] = request.POST['lineclassSelected']
lineclass = valuesquerysettodict(lclass)
return HttpResponse(json.dumps(lineclass), content_type='application/json')
if 'itemSelected' in request.POST:
item = Lineclass.objects.filter(itemname=request.POST['itemSelected'])[0]
diams = Lineclass.objects.filter(itemname=item.itemname).values_list('dn1', flat=True).distinct()
request.session['itemselected'] = request.POST['itemSelected']
diameters = valuesquerysettodict(diams)
return HttpResponse(json.dumps(diameters), content_type='application/json')
if 'diamSelected' in request.POST:
request.session['diameterselected'] = request.POST['diamSelected']
if 'editPrefabQuantityBox' in request.POST:
code = Lineclass.objects.filter(lineclassname=request.session['lineclassselected'])\
.filter(itemname=request.session['itemselected']).filter(dn1=request.session['diameterselected'])[0]\
.code
mat_item.name = request.session['itemselected'],
mat_item.type = 'Prefabrication',
mat_item.lineclass = request.session['lineclassselected'],
mat_item.diameter = request.session['diameterselected'],
mat_item.quantity = request.POST['editPrefabQuantityBox'],
mat_item.workpack = Workpack.objects.get(id=request.session['workpackselected']),
mat_item.code = code,
mat_item.datecreated = datetime.datetime.today(),
mat_item.createdby = request.user.username
mat_item.save()
return HttpResponseRedirect('/prefabs/')
return render_to_response('editprefab.html', context, context_instance=RequestContext(request))
The context['itemid'], context['lineclass'] etc, is where i am grabbing the current values of the item and trying to send them through to the template to be parsed by javascript to set the default values for editing in the select boxes, and provide the items id in the url.
The valuesquerysettodict() function, is a small snippet i found, to convert a Models, values_list into a JSON serializable dict to populate the select based on the parameter that was sent through from Ajax. The reason i am using it, is if i return Lineclass.objects.all(), there are a lot of items in the queryset, with the same name, but different itemcode, so i am using a values_list to try and get unique item names to use with the select.
I am sure i am going wrong somewhere i am just not sure where.
thank you for any help you could give.
So I assume you're making your AJAX call at the click of a submit button. Either way, you can supply the Django variable in the value attribute of any tag and retrieve it like this.
In the value attribute of your submit button, pass the Django ID as such:
<button type="submit" value="{{ material_item.id }}" id="submit-button"></button>
Now, in your AJAX request, you can retrieve the ID and send it with your AJAX request like this:
$(document).ready(function(event){
$(document).on('click', '#submit-button' , function(event){
event.preventDefault();
var pk = $(this).attr('value');
data:{
'id': pk,
}
....
});
});

Grails chain selects without domains

I'm trying to chain two, possibly three <g:select ...> statements together using Ajax like is shown here Populate dropdown list using ajax In grails but all the examples I find have two big differences from what I'm using. 1. I'm using the jQuery library, not prototype. And 2. I don't have domain objects for my select values, they are pulled from an Oracle table via a service call.
My problem looks like this:
<g:select name="degreeSubject" from="${majors}" noSelection="${['':'-Choose Subject-']}" value="${degreeInstance?.degreeSubject }"/>
<g:select name="degreeConcentration" from="${concentrations}" noSelection="${['':'']}" value="${degreeInstance?.degreeConcentration }"/>
Where the majors, and concentrations come through the controller but are populated in a service class.
I was thinking the controller method would look something like
def updateSelect = {
def concentrations = degreeService.getConcentrations(params.selectedValue)
render (template:"selectConcentration", model : ['concentrations' : concentrations])
}
But, I can't get it to work.
Thoughts? Or someone have an example of doing this with jQuery and no domain objects using Grails 2.2.4?
You can really do it without being javascript-library specific. If you use the grails built-in remoteFunction it will handle the jQuery portion for you. What you would then want for your degreeSubject select is:
<g:select name="degreeSubject"
from="${majors}"
noSelection="${['':'-Choose Subject-']}"
value="${degreeInstance?.degreeSubject }"
onChange="${remoteFunction(
controller: 'yourControllerName',
action: 'updateSelect',
params: '\'value=\' + escape(this.value),
onSuccess: 'updateConcentration(data)')}/>
The key being the onChange event calling the remoteFunction. The remote function will make an ajax call to whatever controller action you want, but you'll need to call a javascript function to take in the results of your controller action and populate the other select. If you wanted to do this with simple js you could do this:
function updateConcentration(items) {
var control = document.getElementById('degreeConcentration')
// Clear all previous options
var i = control.length
while (i > 0) {
i--
control.remove(i)
}
// Rebuild the select
for (i=0; i < items.length; i++) {
var optItem = items[i]
var opt = document.createElement('option');
opt.text = optItem.value
opt.value = optItem.id
try {
control.add(opt, null) // doesn't work in IE
}
catch(ex) {
control.add(opt) // IE only
}
}
}
and finally your controller action should look like this:
def updateSelect(value) = {
def concentrations = degreeService.getConcentrations(value)
render concentrations as JSON // or use respond concentrations if you upgrade to 2.3
}

Categories