This is a excerpt of my js file for creating new books in the database and my validation approach for textfields which worked:
//...
function pressHandlerTitle() {
var bookfield = document.getElementById("Book");
if (!bookfield.elements[1].value) {
bookfield.elements[1].setCustomValidity("title must be provided");
} else {
var title = bookfield.elements[1].value;
bookfield.elements[1].setCustomValidity("")
}
if (!(typeof (title) === "string" && title.trim() !== "")) {
bookfield.elements[1].setCustomValidity("The title must be a non-empty string!");
} else {
bookfield.elements[1].setCustomValidity("");
}
bookfield.elements[1].reportValidity();
}
//...
function setupUserInterface() {
const formEl = document.forms["Book"],
otherAvailLangSelEl = formEl["otherAvailableLanguages"],
categoryFieldsetEl = formEl.querySelector("fieldset[data-bind='category']"),
pubFormsFieldsetEl = formEl.querySelector("fieldset[data-bind='publicationForms']"),
saveButton = formEl.commit;
document.getElementById("isbn").addEventListener("keyup", pressHandlerIsbn);
document.getElementById("title").addEventListener("keyup", pressHandlerTitle);
//here there should be the other eventlisteners for the radio button fieldsets
//...
and my HTML looks like this (Flask syntax with Python):
<!-- ... -->
<form id="Book">
<div><label>ISBN: <input type="text" name="isbn" id="isbn"/></label></div>
<div><label>Title: <input type="text" name="title" id="title"/></label></div>
<!-- ... -->
<fieldset data-bind="category">
<legend>Category</legend>
{% for item in ["novel", "biography", "textbook", "other"] %}
<input type="radio" name="unique" value="{{ item }}">{{ item }}<br>
{% endfor %}
</fieldset>
<fieldset data-bind="publicationForms">
<legend>Publication forms</legend>
{% for item in ["PDF", "ePub", "Paperback", "Hardcover"] %}
<input type="checkbox" name="{{ item }}" value="{{ item }}">{{ item }}<br>
{% endfor %}
</fieldset>
Now, I tried to implement live validation in a similar way as for the Title/Isbn textboxes in order to notify the user if no category (e.g. novel && biography && textbook && other is not selected) or no publication form is selected (PDF && ePub && Paperback && Hardcover not selected), but this doesn't work unfortunately. Can you help me on how to add live validation to radio buttons?
I've tried to use different events, e.g. the mouseover event to notify the user of no selected button every time he hovers over the elements of the fieldset. I've tried the getElementsByName function etc. and also tried all methods I found on this site with no success.
Related
I am rendering different groups of radio buttons for product variant options. (For example: a t-shirt can have 3 different radio button groups : size, material, color). Now I am trying to store the user selected radio button values in an array and add the product variant to the cart. I am storing the values with an onclick event on the radio buttons. But because of this, if I change my size choice from XS to S, then both of the XS and S values get added to my array. But I only need the final radio button values to be stored in my array so that I can compare it with my json data and find the variant id. Therefore, I am trying to store all the selected radio button values as an onclick event on the add to cart button, that way it will only store the final selected radio button values. However, I am not sure how to access all the radio button values from different groups in this part. Any help will be appreciated. This is my code so far:
<div class="radios">
{% for product_option in product.options_with_values %}
<p>{{ product_option.name }} -- </p>
{% for value in product_option.values %}
<input type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% endfor %}
<script>
var optionsArray = [];
var filteredOptionsArray = [];
document.querySelector('.radios').addEventListener('click', function(e) {
optionsArray.push(e.target.value);
filteredOptionsArray = optionsArray.filter(function (el) {
return el != null;
});
console.log(filteredOptionsArray);
// console.log(optionsArray.toString());
})
</script>
</div>
<div class="quantity-add">
<div class="input-quantity">
<input class="input-quantity" type="number" min="1" placeholder="1" name="quantity" value="1">
<input type="hidden" id="add-cart" name="id" data-productid="{{ product.variants[0].id }}" value="{{ product.variants[0].id }}" data-variant-title="{{ product.variants[0].title }}" />
</div>
<div class="cart-button">
<button class="cart-btn" type="submit" value="Add To Cart">ADD</button>
<!-- script for adding the selected variant to the cart -->
<script>
document.querySelector('.cart-btn').addEventListener('click', function () {
for (let i=0; i < variantsArray.length; i++) {
if ((JSON.stringify(filteredOptionsArray))== (JSON.stringify(variantsArray[i].options))) {
console.log('stringify match check works');
console.log(variantsArray[i].options);
document.querySelector('#add-cart').value = variantsArray[i].id;
}
else {
console.log('stringify match check failed');
console.log(variantsArray[i].options);
}
}
})
</script>
</div>
found it, I needed to do this:
const checkedRadios = document.querySelectorAll('input[type="radio"]:checked');
const radio_values = Array.from(checkedRadios, radio => radio.value);
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>
Hi I am trying to create a printable page from data send by a form in octobercms
I have created a plugin component which I have called PrintPageForm
<?php namespace Acme\PrintPage\Components;
use Cms\Classes\ComponentBase;
use Input;
class PrintPageForm extends ComponentBase
{
public function componentDetails()
{
// TODO: Implement componentDetails() method.
return
[
'name' => 'Print Page Form',
'description' => 'Detail page print form'
];
}
public function onHandleForm()
{
$var =
[
'overview' => Input::get('print_overview'),
'photos' => Input::get('print_photos')
];
I have this in the default htm file
<form action="/print" data-request-data="printpageform::onHandleForm" data-request-validate data-request-flash accept-charset="utf-8" class="form ajax-form">
<h3 class="sub-heading">Print Details</h3>
<p>To build a printer friendly formatted page, please select from the options shown below:</p>
<ul class="print-section">
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_overview" id="print_overview">
<label class="checkbox-label period" for="print_overview">Overview: Summary and key features alongside a photo of the property.</label>
</li>
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_photos" id="print_photos">
<label class="checkbox-label period" for="print_photos">Photos: Photo gallery of the property.</label>
</li>
</ul>
<input type="hidden" name="print" value="1">
<button class="btn button-large one-third palm-one-whole" type="submit" rel="print" >Print</button>
</form>
I am trying to access the value of print_overview and print_photo values in my print view page but can not figure out how to access these values I can see these values being passed in Debugbar as follows "request_query
array:2 [ "print_overview" => "1" "print" => "1" ]" and in my view file I have
{%if "print_overview" == "1" %}
{{ 'checked' }}
{% else %}
{{ 'Not Checked' }}
{% endif %}
but it does seem to matter what the value of print_overview is the page only echos out Not Checked I'm in a rut that I can't figure out any thoughts would be gratefully accepted.
Couple of pointers. When rendering a form in Twig, you should use either the {{ form_open() }} or {{ form_ajax() }} tags
Secondly, you can access the request data via the post() function in your component class; and you pass it to your view (the component partial) through the page property. So, your handler would like something like:
public function onHandleForm()
{
// Pass the variables to the view renderer
$this->page['print_overview'] = (bool) post('print_overview');
$this->page['print'] = (bool) post('print');
// Return a partial response http://octobercms.com/docs/ajax/update-partials#pushing-updates
return ['#view-response-element' => $this->makePartial('#response')];
}
While your response.htm partial file would look something like this:
{% if print_overview %}
"checked"
{% else %}
"not checked"
{% endif %}
As a note, if you are using the {% macro %} tags, these do not have access to the local scope of the partial file, i.e. they do not have access to the variables provided to the view. Any evaluation done within {% macro %} tags needs to be based on variables passed to it.
The best strategy for printing I find is to use JavaScript:
<!-- Link to print -->
<p>Print this invoice</p>
<!-- Invoice printer -->
<script type="text/template" id="invoiceTemplateContents">
Printable contents go in here
</script>
<!-- Script -->
<script>
function printInvoice() {
var printWindow = window.open('','','left=0,top=0,width=950,height=500,toolbar=0,scrollbars=0,status=0')
printWindow.document.write($('#invoiceTemplateContents').html())
printWindow.document.close()
printWindow.focus()
printWindow.print()
printWindow.close()
}
</script>
So I am new to Django and a complete novice at JavaScript. I am trying to create a view which renders multiple forms dynamically using JavaScript. Below are two forms that I have created.
class CreateTestForm(forms.ModelForm):
class Meta:
model = Test
fields = ['name', 'test_group', 'description', 'query_text', 'failure_condition', 'status']
def getKey(self):
return "create_test_form"
class VC1Form(CreateTestForm):
expected_relation = forms.ChoiceField(choices = [('<','<'), ('>','>'), ('=','='), ('<=','<='), ('>=','>='), ('!=','!=')], required = True, label = 'Expected Relation: ')
num_rows = forms.IntegerField()
def getKey(self):
return "vc1_form"
In addition, I have the following view
def create_test(request):
context = {
'all_validation_classes': ValidationClass.objects.all()
}
for form in [CreateTestForm, VC1Form]:
if request.method == 'POST':
f=form(request.POST)
if (f.is_valid()):
return HttpResponseRedirect('/test_created/')
else:
return HttpResponseRedirect('/test_not_created/')
else:
f = form()
context[f.getKey()] = f
return render(request, 'create_test.html', context)
And template:
<form action="/tests/create/" method="post">
{% csrf_token %}
{{create_test_form.as_ul}} <br><br>
<select id="validation_classes_id" name="all_validation_classes" onchange="showForm()">
<option value="%">Choose the validation class</option>
{% for val_class in all_validation_classes %}
<option value="{{ val_class.id }}">{{ val_class.id}} {{val_class.name }}</option>
{% endfor %}
</select>
<br><br>
<script>
function showForm(){
var x = document.getElementById("validation_class_id").value;
}
</script>
<input type="submit" value="Submit" />
I am trying to get to a point, where, when the user selects something from the dropdown (validation_classes_id), the view will render the form corresponding to that selection. I have currently included only one additional form VC1Form here but I have written different forms corresponding to each option in the drop down.
I have tried a few things but nothing has worked yet and any help would be appreciated!
Try something this:
document.getElementById('form').querySelectorAll("label").forEach( e =>
{e.prepend(document.createElement("br"));});
Even better would be:
<form id="form" action="login_view" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="register">
I have this code of HTML (Django + Jinja) .
<div class="span10 well">
{% for k in values.chat %}
<label> Text : {{k.text}} </label>
<label> {{k.date_time}} </label>
{% endfor %}
<form action = "#" method = "POST" id = {{key}} name = "reply_form">
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "Sent" class="btn btn-primary">
</form>
</div>
Since, there will be many chats and correspondingly reply submit button and its key, I want that when I reply to a specific chat, it carries the key with itself and process the chat accordingly.
What I need is to append the url with the form id parameter. How can I achieve this?
You can create a hidden input field
<input type="hidden" name="chat_key" value="{{key}}">
This way you can track which chatroom the person is responding by setting the value to the id of the chatroom.
EDIT: Since you are using django, on the backend to get the value of the chat_key you can just do this:
chat_key = form.cleaned_data['chat_key']