The following flask code creates a select .. option dropdown menu:
model:
class SelectForm(Form):
country = SelectField('Country', choices=[
('us','USA'),('gb','Great Britain'),('ru','Russia')])
flask app:
#app.route('/new')
def new():
form = SelectForm()
return render_template('new.html', form = form )
html file:
<form method=post action="/register">
{{ render_field(form.country) }}
<p><input type=submit value=Register>
</form>
macro file the defines render_field:
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
What is the best way to have onchange submit the results automatically without the user having to press the submit button? Is there a way to change the macro or what's the most elegant way?
thanks
It can be done by add javascript onchange function as attribute
<form method=post action="/register">
{{ render_field(form.country(**{"onchange":"this.form.submit()"})) }}
<input type=submit value=Register>
</form>
Related
I have rendered the product variants as radio buttons on liquid. Now I am trying to listen to the variant change and render different prices accordingly. However, I do not know how to listen to the variant change here.
Here is my code:
<form>
{% for product_option in product.options_with_values %}
{{ product_option.name }}
{% for value in product_option.values %}
<input type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% assign current = product.selected_or_first_available_variant %}
{% endfor %}
<p>Price: {{current.price}} </p>
<input type="number" min="1">
<button type="submit">Add to Cart</button>
</form>
The price only shows for the first available variant. Even when I select different radio button options, the variant price does not update.
Welcome to stack overflow
Ideally, you probably should use some classes to use for your listeners as the page can have different radio buttons possibly even in other forms.
Below probably would get you going in the right direction.
<form>
{% for product_option in product.options_with_values %}
{{ product_option.name }}
{% for value in product_option.values %}
<input class="option" type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% assign current = product.selected_or_first_available_variant %}
{% endfor %}
<p>Price: <span id="variantPrice">{{current.price}}</span></p>
<input type="number" min="1">
<button type="submit">Add to Cart</button>
</form>
You haven't mentioned if you are using jquery or not.
I'm going to assume you are.
<script>
$( document ).ready(function() {
// Load all product data to an object
var productData = {{ product | json }};
// Listen to radio button updates and trigger a function to identify the variant
$('.option').change(function() {
idSelectedVariant();
});
function idSelectedVariant(){
//1. Loop through the options and identify the selected options
//2. Once the selected options are identified, loop through the variants in the productData object and identify the selected variant by checking the variant options
//3. Keep in mind that not all product variants are going to have 3 options all the time. Some products can have 1 or 2 options as well.
//4. Once the relevant variant is identified display the variant price by updating the content in the variantPrice span.
}
});
</script>
I want to implement on the web page the sequential display of blocks with data input (i.e. after filling in the first block and pressing the "OK" button, the second block opens, then the third). The button in the last block sends a request to write data.
The problem is that with the help of reguest.form.get I can only receive data from the form in which the button is located. How can I get data from other forms?
I am new to Flask and my code may not be very correct. Maybe you should use javascript?
flask.py
#app.route('/scenario',methods = ['GET', 'POST'])
def control_task():
if(request.form.get('add') == 'add'):
ts.add_task(request.form['host_info'].get('task'),request.form['host_info'].get('hostId'), request.form['role_info'].get('role'))
html:
<button id='addTask_btn' onclick="hidden_element(addTask_block)">add task</button>
<span id="addTask_block" hidden="true">
<form name="host_info">
<select name="task">
{% for test in tests %}
<option>{{test}}</option>
{% endfor %}
</select>
</form name='service_info>
<button onclick="hidden_element('step_2')">Ok</button>
<div hidden="true" id="step_2">
<form name="service_info">
<select id="service" name="service">
{% for role in hosts[0].roles %}
<option value="{{role.serviceName}}">{{role.serviceName}}</option>
{% endfor %}
</select>
</form>
<button onclick="hidden_element('step_3')">Ok</button>
<button onclick="hidden_element('step_3')">Back</button>
</div>
<div id="step_3" hidden="true">
<form method="post" action="/scenario" name="role_info">
<select name="role">
{% for role in hosts[0].roles %}
<option name="{{role.roleType}}">{{role.roleType}}</option>
{% endfor %}
</select>
<button onclick="hidden_element(step_3)" name="add" value="add">Ok</button>
</form>
</div>
</span>
<script type="text/javascript">
function hidden_element(id){
document.getElementById(id).hidden = !document.getElementById(id).hidden;
}
</script>
im trying to send requests without refreshing the pae using ajax requests.
Watching the google event listerner when i i click the submit button my script is not begin called.
script.js
$("#new_app_b").click(function(event) {
//prevent submit
event.preventDefault();
//do things on submit
$.ajax({
data : {
data_app : $('#data_app').val(),
time_app : $('#time_app').val(),
id : $('#id').val()
},
type: "POST",
url: "/update",
beforeSend: function(){
//before send data
},
success: function(data){
// the data
console.log(data);
}
});
});
in layout.html i call this in the
in page html the part with the form is like this it has the {% extends 'layout.html' %} and the form is the the blockcontent and is begin displayed correctly it has 300+ lines so i wont post it all.
<form action="/update" method='POST' id="new_app">
<input name="id" id="id" type="hidden" value="{{ pratica[0][1] }}">
</input>
{% for cell in pratica %}
{% if cell[0] == 'data_app' %}
<td><input name="data_app" id="data_int" class="form-control form-control-sm"
type="text" value="{{ cell[1] }}"/></td>
{% elif cell[0] == 'time_app' %}
<td><input name="time_app" id="ora_app" class="form-control form-control-sm"
type="text" value="{{ cell[1] }}"/></td>
{% endif %}
{% endfor %}
<td>
<button id="new_app_b" type="submit" class="btn btn-success">
<i class="fa fa-check"></i>
</button>
</td>
</form>
while the /update controller is just like:
#app.route("/update", methods=['GET','POST'])
def update():
print("request: ")
print("id: " + request.form['id_pratica'])
print("data_app: " + request.form['data_app'])
print("time_app: " + request.form['time_app'])
return ''
So ive found the solution and this is what i did:
I moved the into the child template, using a block block like so:
{% block scripts %}
{{ super() }}
<script type="text/javascript" src="{{ url_for('static',filename='js/script.js') }}"></script>
{% endblock %}
and put that block on top of the content block, and then i call the block in the layout.html file like so
{% block scripts %}{% endblock %}
in the tag, and now is begin loaded and called when it needs to.
I'm trying to replace a 'reply' button with a form in my Django app.
Here's my Javascript code:
$(document).on('click', '.comment-reply-link', function(e) {
$(this).replaceWith("<form method='post'>{% csrf_token %}<div class='form-group'><label for='comment'>Comment:</label><textarea class='form-control' id='comment' rows='5' maxlength='300' minlength='1' name='comment' placeholder='Tell us how you loved this product :D'></textarea></div><button type='submit' name='post_comment' value='True'>Comment</button></form>");});
// The replacing line should contain no whitespace.
// Otherwise it will raise Uncaught SyntaxError: Unexpected token ILLEGAL
I get the form element but the problem is that {% csrf_token %} is processed as just unicode in replaceWith(). {% csrf_token %} is necessary in Django to submit a form. Any kind of help and advice will be thankful :)
Edit:
I assume that {% %} means that Django needs to be involved to retrieve the right value. So I thought I should render an html page with form and update that form with 'reply' button. Here's my logic.
view.html
<div class="reply">
<a class='comment-reply-link' href='{% url "rango:reply_form" %}'aria-label='Reply to Araujo'>Reply</a>
</div>
reply.js
function ajax_get_update(item){
$.get(url, function(results){
//get the parts of the result you want to update. Just select the needed parts of the response
// var reply_form = $("#reply_form", results);
var reply_form = $(".head", results);
console.log(reply_form);
//console.log(results);
//update the ajax_table_result with the return value
$(item).html(reply_form);
}, "html");
}
$(document).on('click', '.reply', function(e) {
console.log("Debuggin...");
e.preventDefault();
url = ($( '.comment-reply-link' )[0].href);
console.log(url);
ajax_get_update(this);
});
reply_form.html
<!DOCTYPE html>
... code omitted ....
<form id="reply_form" method="post">
{% csrf_token %}
<div class="form-group">
<label for="comment">Reply:</label>
<textarea class="form-control" id="comment" rows="5" maxlength="300" minlength="1" name="comment" placeholder="Tell us how you loved this product :D"></textarea>
</div>
<button type="submit" name="post_comment" value="True">Reply</button>
</form>
</body>
</html>
When I click the reply button, the button disappears but nothing updates. The html page variable results gets the correct html page data but it seems like
$(item).html(reply_form);
is not working right. Because when I do
$(item).html('<p>button disappears</p>');
the paragraph will appear. Any thoughts?
To use django template language in javascript you should encapsulate your code in a Verbatim tag.
example :
{% verbatim %}
var hello = {% if some_condition %} 'World' {% else %} 'foobar' {% endif %};
{% endverbatim %}
From the docs :
Stops the template engine from rendering the contents of this block tag.
A common use is to allow a JavaScript template layer that collides with Django’s syntax
In your case :
<script>
{% verbatim %}
$(document).on('click', '.comment-reply-link', function(e) {
$(this).replaceWith("<form method='post'> {% csrf_token %} </form>")
};
{% endverbatim %}
</script>
I'm trying to port an application with an existing db. I'm using db_column to have django model Foreign Keys correctly while using the existing database names and columns.
models.py
class foo(models.Model):
foo_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_name = models.CharField(max_length=500, blank=True, null=True)
foo_type_lookup = models.ForeignKey('foo_type_lookup', to_field="foo_type_id", db_column="foo_type", blank=True, null=True)
class foo_type_lookup(models.Model):
foo_type_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_type = models.CharField(max_length=500, blank=False, null=False)
The table foo_type_lookup has two rows (ids 0 and 1) for foo_type 'bar' and 'baz'. I'm trying to make a form to add a record in the foo table which will have a foreign key to foo_type_lookup. Foo can either be bar or baz.
views.py
def add_foo(request):
action = '#'
errors = None
if request.method == 'POST':
form = FooForm(request.POST)
if form.is_valid():
form.save(commit=True)
return home(request)
else:
# The supplied form contained errors - just print them to the terminal.
errors = form.errors
else:
# If the request was not a POST, display the form to enter details.
form = FooForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'foo/add_foo.html', {'form' : form, 'errors' : errors, 'action' : action})
forms.py
CONTACT_FOO_CHOICES = [[0,'Bar'],[1,'Baz']]
class FooForm(forms.ModelForm):
foo_type_lookup = forms.ChoiceField(widget=RadioSelect(), choices=CONTACT_FOO_CHOICES)
foo_name = forms.CharField(label='First Name', max_length=500, required=False)
class Meta:
model = foo
fields = ('foo_name','foo_type_lookup')
I have to iterate over the form object in my template so I can add a jQuery function when the radio buttons are changed. I find this pretty clunky, but I'm not sure of a more django way to accomplish this:
add_foo.html
<h2>add_foo.html</h2>
<form action="{{action}}" method="post" role="form">
{% csrf_token %}
{% for field in form %}
{% if field.auto_id = 'id_foo_type_lookup' %}
{% for choice in form.foo_type_lookup.field.choices %}
<li>
<label for="id_{{ field.html_name }}_{{ forloop.counter0 }}">
<input type="radio"
id="id_{{ field.html_name }}_{{ forloop.counter0 }}"
value="{{ choice.0 }}"
{% if choice.0 == '0' %}
checked="true"
{% endif %}
name="{{ field.html_name }}"
onchange="someFunction('id_{{ field.html_name }}_{{ forloop.counter0 }}')"/>
{{ choice.1 }}
</label>
</li>
{% endfor %}
{% else %}
<div class="formfield_err">{{ field.help_text }}</div>
<div id="{{ field.auto_id }}_container" >
<div class="formfield_divlbl">{{ field.label_tag }}
</div>
<div class="formfield_divfld">{{ field }}
{% if field.field.required %}
<span class="required">*</span>
{% endif %}
</div>
<div id="{{ field.auto_id }}_errors">{{ field.errors }}
</div>
</div><div class="clear" style="margin-bottom:12px;"></div>
{% endif %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
I get the error:
Cannot assign "'0'": "foo.foo_type_lookup" must be a "foo_type_lookup" instance.
How do I layout the radio buttons for the type lookup to add onchange javascript and supply my ModelForm with an object of 'foo_type_lookup' so the data will save to the database?
A ChoiceField does not know it needs to coerce the provided value to a particular model instance.
Use a ModelChoiceField instead.
https://docs.djangoproject.com/en/1.7/ref/forms/fields/#modelchoicefield
Whoops, it seems you want some very specific display logic for your values hard coded into your python which may not necessarily equate to your string representations of your related model.
If so, override your form save to apply any coercion there before the real save gets called via super.
You can also manually apply any python logic via commit=False (I notice you already have that statement set to True and perhaps you were playing with the idea.)
obj = form.save(commit=false)
obj.foo_lookup_type = MyObject.objects.get(pk=form.cleaned_data['foo_lookup_type'])
obj.save()