trigger javascript function based on python variable value - javascript

The following 2 js functions can toggle a button to and from the disabled class. I want the disabled state to depend on the global variable filelength in the python code but cannot think of a simple way to do so. The only way I can think of is to have 2 identical but separate templates, one with the button disabled and one with it enabled.
<script type="text/javascript" language="JavaScript">
function enableButton(button){
document.getElementById(button).removeAttribute('class');
document.getElementById(button).setAttribute("class", "button");
}
function disableButton(button){
document.getElementById(button).setAttribute("class", "disabled");
}
</script>
I intended to use the functions for the following index.html template element.
<button id="Test" class="button disabled" >
Test
</button>
The intended toggling would produce the following alt.html template element which elides the "disabled".
<button id="Test" class="button" >
Test
</button>
It seems silly to require 2 separate templates (index.html and alt.html) to accomplish this toggle, but I cannot think of an alternative that permits me to just alter index.html. Initially I thought jinja2 would provide the functionality needed, but that does not seem correct.
How can I accomplish this without a second template using python and GAE?
For more completeness, below I show the relevant state of my python application next.
import os
import jinja2
import webapp2
import urllib
filelength = 0
class MainPage(BaseHandler):
def get(self):
global filelength
logging.info("text length in Main get: %s " % filelength)
template_values = {'filelength':filelength}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.out.write(template.render(template_values))
def post(self):
global filelength
url = self.request.get('URL', None)
text = urllib.urlopen(url).read()
logging.info("text length in Main post: %s " % len(text))
filelength = len(text)
if filelength > 0:
return webapp2.redirect('/alt')
else:
return webapp2.redirect('/')
class AltMainPage(BaseHandler):
def get(self):
global filelength
logging.info("text length in Alt get: %s " % filelength)
template_values = {'filelength':filelength}
template = JINJA_ENVIRONMENT.get_template('alt.html')
self.response.out.write(template.render(template_values))
def post(self):
global filelength
url = self.request.get('URL', None)
text = urllib.urlopen(url).read()
logging.info("text length in Alt post: %s " % len(text))
if filelength > 0:
return webapp2.redirect('/alt')
else:
return webapp2.redirect('/')
return webapp2.redirect('/')
app = webapp2.WSGIApplication([
('/', MainPage),
('/alt', AltMainPage),
],
debug=True)

In the template index.html simply use jinja2 to define the class attribute like this where the value of buttonclass is defined as either button or button disabled in python using the "if ... else" construct.
<button id="Test" class="{{ buttonclass }} " >
Test
</button>

Related

Kendo UI - Set parameter programmatically

# var myVar = false; #
<div>
#(Html.Kendo().Stepper()
.Name("stepper")
.Orientation(StepperOrientationType.Horizontal)
.Label(true)
.Indicator(true)
.Steps(s =>
{
s.Add().Label("Step_1");
s.Add().Label("Step_2").Selected(true);
s.Add().Label("Step_3");
})
.ToClientTemplate())
</div>
The above sets Step_2 to be the selected one.
How do I set it programmatically?
e.g. s.Add().Label("Step_2").Selected(myVar);
You are messing languages layers. myVar is Javascript and its inside a template, Html.Kendo()... is c#, so you CAN'T mix them. You have to change it outside the template.
What I would do is something like this:
<div id="stepper-container" data-step="#= myVar #">
Then after the template was rendered, I would use Javascript to change that:
let stepperIndex = $('#stepper-container').data('step');
$('#stepper').data('kendoStepper').select(stepperIndex);

How to create language selection wrapper from a gist script?

I have a Gist file written in different languages all do the same thing.
So, I would like to create a language select option similar to Google docs documentation.
Is it possible to create such a wrapper class that accepts a Gist script tag and display as above?
As in embed single file, I tried different query command like <script src="https://gist.github.com/gistid.js?language=python">, but none of them work.
This is the processing code that I ended up with.
With some CSS + javascript hide and toggle logic, it would work like google docs documentation.
I'd appreciate it if anyone updates this answer, with css or js.
import requests
from bs4 import BeautifulSoup
def render_gist_by_file(gist_id):
result = requests.get(f'https://gist.github.com/{gist_id}.js', headers=git_credential)
if result.text.startswith("<!DOCTYPE html>"):
return None
result = result.text
result = result.replace("\\/", "/").replace("\\&", "&").replace("\\$", "$").replace("\\<", "<").replace("\\`", "`").replace("\\n", "\n").replace('\\"', '"')
result = html.unescape(result)
result = result.split("document.write('")[-1][:-3]
bs = BeautifulSoup(result, "html.parser")
for tag in bs.find_all(class_="gist"):
file_box = tag.find(class_="file-box")
root = tag.find(class_="file-box")
toggle_div = bs.new_tag('div', attrs={"class": "gist-meta"})
for i, d in enumerate(tag.find_all(class_="file")):
d["class"] = f"file gist-toggle gist-id-{gist_id}"
if i != 0:
file_box.append(d) # combine to first table
for d in tag.find_all(class_="gist-meta"):
siblings = list(d.next_elements)
file_id, file_name = siblings[4].attrs["href"].split("#")[-1], siblings[5]
gist.file_names.append(file_name)
toggle_a = bs.new_tag('a', attrs={"id": file_id, "class": f"gist-toggle gist-id-{gist_id}", "onclick": f"toggle('gist-id-{gist_id}', '{file_id}')", "style": "padding: 0 18px"})
toggle_a.append(file_name)
toggle_div.append(toggle_a)
d.extract() # remove bottom nav
root.insert(0, toggle_div)
for d in islice(tag.find_all(class_="gist-file"), 1, None):
d.extract() # remove except first
gist.html = str(bs)
return gist

Mandatory slider in oTree/django

I want to use oTree as an alternative for conducting experiments. For this purpose I am looking for a possibility to include mandatory slider questions in forms, i. e. sliders you are required to move before you are able to proceed to the next question. As a start I tried to modify oTrees survey template to achieve a solution for future usage but wasn't able to integrate common approaches like a fieldtracker into the project.
Here are two modified (yet currently after a number of unsuccessful try-outs not really functioning) versions of the models.py and views.py files which give a hint in which direction I want to go. Is there a way to get this to work?
# -*- coding: utf-8 -*-
## models.py
# <standard imports>
from __future__ import division
from django.db import models
from django_countries.fields import CountryField
from model_utils import FieldTracker,
from otree import widgets
from otree.constants import BaseConstants
from otree.db import models
from otree.models import BaseSubsession, BaseGroup, BasePlayer
class Constants(BaseConstants):
name_in_url = 'survey'
players_per_group = None
num_rounds = 1
class Subsession(BaseSubsession):
pass
class Group(BaseGroup):
pass
class Player(BasePlayer):
def set_payoff(self):
"""Calculate payoff, which is zero for the survey"""
self.payoff = 0
q_country = CountryField(
verbose_name='What is your country of citizenship?')
q_age = IntegerFielder(verbose_name='What is your age?',
min=13, max=125,
initial=25,
widget=widgets.SliderInput())
q_gender = models.CharField(initial=None,
choices=['Male', 'Female'],
verbose_name='What is your gender?',
widget=widgets.RadioSelect())
tracker = FieldTracker()
crt_bat = models.PositiveIntegerField()
crt_widget = models.PositiveIntegerField()
crt_lake = models.PositiveIntegerField()
Here comes the second file:
# -*- coding: utf-8 -*-
##views.py
from __future__ import division
from . import models
from ._builtin import Page, WaitPage
from otree.common import Currency as c, currency_range
from .models import Constants, integerfieldcustom
class Demographics(Page):
form_model = models.Player
form_fields = ['q_country',
'q_age',
'q_gender']
check_age = q_age.tracker.has_changed()
def q_age_error_message(self, ):
if Demographics.check_age == False:
return 'You must move the slider before you can continue'
class CognitiveReflectionTest(Page):
form_model = models.Player
form_fields = ['crt_bat',
'crt_widget',
'crt_lake']
def before_next_page(self):
self.player.set_payoff()
page_sequence = [
Demographics,
CognitiveReflectionTest
]
Thanks in advance!
There are two ways of doing it: by using JS only, on the client's side, and by using Django at the server side.
The simple JS solution:
in the template add:
{% block scripts %}
<script>
var SliderTouched = false;
var selector = $('[data-slider] input[type="range"]');
selector.change(function() {
SliderTouched = true;
});
$( ".form" ).submit(function( event ) {
if (!SliderTouched){
event.preventDefault();}
});
</script>
{% endblock %}
So until the user triggers change event, the SliderTOuched var is set to False which prevents a form to be submitted. It is a compact way, but you have to deal with showing an error message to the user yourself.
=================
The longer server-side solution is the following:
in models.py define an additional field:
class Player(BasePlayer):
checkslider = models.IntegerField(blank=True)
in views.py in addition to your slider field pass also this extra field that will check that the slider was changed:
class MyPage(Page):
form_model = models.Player
form_fields = ['q_age', 'checkslider']
def checkslider_error_message(self, value):
if not value:
return 'Please make your decision using slider'
in template insert this hidden extra field to html:
<input type="hidden" name="checkslider" value="" id="id_checkslider"/>
and set this field to current slider value as soon as slider is changed:
{% block scripts %}
<script>
var selector = $('[data-slider] input[type="range"]');
selector.change(function() {
$('#id_checkslider').val(selector.val());
});
</script>
{% endblock %}
By default, Django assumes an input is required.
I think that means if you just remove the initial value, it will self-validate.
Also, you called something named "IntegerFielder()." Did you mean models.IntegerField() or is there an import that we're not seeing?
I suggest a slight modification to Philipp's answer.
The code above still triggers the error message if the participant touches the slider, but returns the slider to the default starting position.
To fix this, I used the following script:
{% block scripts %}
<script>
$('input[name=q_age]').on('input', function(){
$('#id_checkslider').val(1);
});
</script>
{% endblock %}
The code changes checkslider from None to 1 when the slider is touched, even if the participant sets the slider to the default starting position.

How to use the value of <select> in with django function?

So I want to make a function with if in my html using django.
My function looks like :
function try() {document.getElementById("demo").inerHTML = '{%for x in xl%}'+
'{%if x.name == document.getElementById("select1").value%}'+
'<button type="button">hello</button>'+
'{%endif%}{%endfor%}'}
And the relevant html is :
<select id="select1">
<option value = "tiger"></option>
<option value = "bear"></option>
<option value = "eagle"></option>
</select>
<p id="demo"></p>
<script>try();</script>
So just to make it clear :
'xl' is a list, the items in this list have a name variable.
I want my web to show in the "demo" paragraph 'hello' buttons for each time that the selcted animal is the name of item in the list.
When trying to run this it says : " Could not parse the remainder: '("select1").value;' from 'document.getElementById("select1").value;' "
Please help me find what`s wrong and how to fix it, Thanks.
Why not just use a Django form, and then get the selected option value with JavaScript? Example code has not been tested. You still need an app within your Django project, settings, templating, routing, etc.
# forms.py
class AnimalForm(forms.Form):
TIGER = 'Tiger';
BEAR = 'Bear'
EAGLE = 'Eagle'
ANIMAL_CHOICES = (
(TIGER, TIGER,),
(BEAR, BEAR,),
(EAGLE, EAGLE,),
)
animal = forms.CharField(max_length=20, choices=ANIMAL_CHOICES,
default=TIGER)
def save(self):
return NotImplementedError
# implement
# views.py
from django.shortcuts import render
from .forms import AnimalForm
def choose_animal(request):
form = AnimalForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
form.save()
# do something, like redirect to a success page, etc
return render(request, 'animal_form.html',
{'form': form})
#animal_form.html
<form action="." method="post" enctype="application/x-www-form-urlencoded">
{{ form.animal }}
<button type="submit">Save</button>
</form>
<p id="animal-selection"></p>
<script>
// assuming jQuery is already linked for brevity
(function($) {
$(function() {
$('#id_animal').on('change', function() {
$('#animal-selection').html($(this).val());
});
});
})(jQuery);
</script>

AttributeError: 'unicode' object has no attribute 'get' - In Django Forms

I'm trying to use Django Forms with Ajax Calls.
Previously I just used a html form that I could get all the information through request.POST['item']. But I've been thinking about validators, and I would benefit if I switched normal html forms into Django forms.
In my HTML code (the page where the user clicks, and a AJAX calls another view with javascript):
if not request.user.is_authenticated():
#Tells the user to login if not authenticated
return redirect('/webapp/login.html')
else:
#Get Logger
logger = logging.getLogger('views.logger.chartConfigure')
logger_uuid = uuid.uuid4()
logger_time = datetime.datetime.now()
#Log the User
logger.info("Request in editChart, User:" + str(request.user.username) + ", UUID:" + str(logger_uuid) + ", Time:" + str(logger_time))
#Forms to use
chartName = changeChartNameForm(auto_id=False)
#Put Forms into a context
context = {'chartNameForm': chartName}
#Return the context
return render(request, 'webapp/editChart.html', context)
The Forms that are used is a changeChartNameForm:
#Form for editing chart names
class changeChartNameForm(forms.Form):
#Only one variable which is called chartName, with label set to ""
#Since I don't want any labels. I have my own in HTML.
chartName = forms.CharField(max_length=100, label="")
#form-control is an extra class that is required by bootstrap 3, and the html id
#of the form is called chartName
chartName.widget.attrs['class'] = 'form-control'
chartName.widget.attrs['id'] = 'chartName'
HTML Code:
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="newChartName" >New Chart Name</button>
</span>
{{ chartNameForm }}
</div>
The Javascript code:
$.ajax(
{
type:"POST",
url:"ajax_postColumnAction/",
datatype: 'json',
data:
{
'csrfmiddlewaretoken':csrftoken,
'currentTabSelected':currentTabSelected,
'currentColumnSelected':currentColumnSelected,
'action':'changeName',
'changeNameForm':$('#chartName').serialize()
},
success: function(response)
{
...Some logic happens here
}
}
basically the javascript code will call this view, called ajax_postColumnAction:
#Get the name form, and get the newName
changeNameForm = changeChartNameForm(request.POST['changeNameForm'])
newName = ""
if(changeNameForm.is_valid()):
newName = changeNameForm.cleaned_data['chartName']
The return is always:
'unicode' object does not have the attribute 'get' at the following line: if(changeNameForm.is_valid())
I have tried the following:
using data=request.POST
using data=request.POST['changeNameForm']
Full Traceback:
Traceback (most recent call last):
File "C:\Users\Desktop\Dropbox (Personal)\Django\Dashboard_Web\WebApp\views.py", line 738, in ajax_postColumnAction if(changeNameForm.is_valid()):
File "C:\Python27\lib\site-packages\django\forms\forms.py", line 129, in is_valid return self.is_bound and not bool(self.errors)
File "C:\Python27\lib\site-packages\django\forms\forms.py", line 121, in errors self.full_clean()
File "C:\Python27\lib\site-packages\django\forms\forms.py", line 273, in full_clean self._clean_fields()
File "C:\Python27\lib\site-packages\django\forms\forms.py", line 282, in _clean_fields value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
File "C:\Python27\lib\site-packages\django\forms\widgets.py", line 207, in value_from_datadict return data.get(name, None) AttributeError: 'unicode' object has no attribute 'get'
Edit:
When I Do:
print request.POST['changeNameForm']
I get chartName = "some text I typed in the browser"
This part of the error says that data is an unicode string:
return data.get(name, None) AttributeError: 'unicode' object has no attribute 'get'
data needs to be an object. Instead, it is a string, and strings don't have a get() method, and don't have name attributes as the error trace back says.
Try going off of the Django Docs to properly call the AJAX:
https://docs.djangoproject.com/en/1.6/topics/class-based-views/generic-editing/#ajax-example
It seems that a workaround is to construct the form in the view.
I've looked at tenths and hundreds of StackOverFlow posts and Google websites, and non seem to have my problem.
The method is to recreate the form when you get the POST data, since a form uses a dictionary as a constructor.
changeNameForm = changeChartNameForm({request.POST['changeNameForm'].split("=")[0]}):request.POST['changeNameForm'].split("=")[1]})
I know that request.POST['changeNameForm'] returns a string "chartName=someName". I split the string with "=", and I would get someName, and chartName. Hence I would put someName into a dictionary, with the key called chartName.
{'chartName':'someName'}
Hence the form is recreated with the post data and finally passes is_valid.

Categories

Resources