I am developing a search engine for a website; now it's working fine and responding to input search keywords with no issues in its interaction with the (Django-based) local web server. The problem (well there are actually two, but I'm presenting only one here) is with the datalist. When I select an option from the list, although it goes into the search input field, nothing happens until I click the submit button.
I have written an event listener for each option, but I'm clearly missing something (important). Here's my minimal working code:
const searchForm = document.getElementById('search-form');
const enter = document.getElementById('enter');
let options = document.querySelectorAll(".option");
options.forEach((item, index) => {
item.addEventListener("click", () => {
return searchForm.action;
})
})
<form id="search-form" action ="{% url 'search' %}" method='POST'>
{% csrf_token %}
<input id="enter" type="search" list="options" name="query" />
<datalist id="options">
<option class="option" value="Happy">
<option class="option" value="Puzzled">
</datalist>
<button id="go" type="submit"><strong>🔎︎</strong></button>
<button id="reset" type="reset"><strong>X</strong></button>
</form>
Maybe the event should be something else; I've tried "keydown" and clicking twice but nothing has worked.
Try using the input event fired on the input element. The input event's data property only shows the latest addition to the input's value by clicking an option, typing or pasting, while the value property shows everything entered. Check it out in the snippet.
The event listeners on the option elements never get called - probably best to leave them out.
"use strict";
const enter = document.getElementById('enter');
let options = document.querySelectorAll(".option");
options.forEach((item, index) => {
item.addEventListener("click", () => {
console.log("clicked option ", this.value);
return searchForm.action;
})
// debug:
enter.oninput = e=>console.log('event.data: %s, enter.value: %s',e.data,enter.value);
})
<form id="search-form" action ="" method='' onsubmit="console.log(event);return false">
<input id="enter" type="search" list="options" name="query" />
<datalist id="options">
<option class="option" value="Happy">
<option class="option" value="Puzzled">
</datalist>
<button id="go" type="submit"><strong>🔎︎</strong></button>
<button id="reset" type="reset"><strong>X</strong></button>
</form>
In answer to my question, here is a solution I adapted from an article by Keith (2020) which worked for me:
JavaScript
const enter = document.getElementById('enter');
document.querySelectorAll('#enter[list]').forEach( function (formfield) {
var options = document.getElementById('options');
var lastlength = formfield.value.length;
var checkInputValue = function (inputValue) {
if (inputValue.length - lastlength > 1) {
options.querySelectorAll('option').forEach( function(item) {
if (item.value === inputValue) {
formfield.form.submit();
}
});
}
lastlength = inputValue.length;
};
formfield.addEventListener('input', function () {
checkInputValue(this.value);
}, false);
});
Reference:
Keith, J. (2020) Submitting a form with datalist. Available from: https://adactio.com/journal/17337 [Accessed October 31, 2022]
Related
This is the book now button from page 1, product.html
<form name="booksr1" method="link" action="enquiry.html"><input type="button" value="Book Now" class="book" onclick="window.location.href='enquiry.html'" /></form>
I'd like to make it where the other page, enquiry.html is prefilled with the subject I want e.g. RE: Enquiry on: Single Room, when the "Book Now" button on the other page is clicked on
This is the code for the RE: Enquiry input on page 2.
<label for="RE: Enquiry on:">RE: Enquiry on:<span class="RequiredColor">*</span></label><br/>
<input type="text" id="Subject"/><br/><br/>
How should I do this with localstorage?
P.S. I'm quite new to this so please make it simple to understand. THANKS!!!
StackOverflow doesn't allow you to save/read from localStorage, so you can't click the buttons to see it work, but let's give this a go. There might be some errors, it's late, but I hope I can explain.
Let's say you have product.html:
function go() {
var room = document.querySelector('#room-select').value;
localStorage.setItem('room', room);
location.href="enquiry.html";
}
<label for="room-select">Choose a Room:</label>
<select id="room-select">
<option value="1">Single Room</option>
<option value="2">Double Room</option>
<option value="3">Triple Room</option>
</select>
<button onclick="go()">Submit</button>
You run a function that gets the value of the select box, stores it in localStorage and then goes to your enquiry page.
Now you have to add some script to enquiry.html to read the value back out.
document.addEventListener('DOMContentLoaded', () => {
var room = localStorage.getItem('room');
var input = document.querySelector('#subject');
input.value = room;
});
<label for="subject">RE: Enquiry on:</label>
<input type="text" id="subject" name="name" required>
You have to wait for the page to load (listen for the event DOMContentLoaded), then read the value you stored on the previous page, get a reference to the input box and update its value with the one you read from storage.
****LATEST UPDATE***
I've added and editted the codes Will suggested(Thanks!! :D) into my product.html,
function room1() {
var room = document.querySelector('#room-selector-one').value;
localStorage.setItem("booking1", "Single Room(Fan)");
location.href="enquiry.html";
}
function room2() {
var room = document.querySelector('#room-selector-two').value;
localStorage.setItem("booking2","Single Room(AC)");
location.href="enquiry.html";
}
and my enquiry.html.
document.addEventListener('DOMContentLoaded', () => {
var room = localStorage.getItem('booking1');
var input = document.querySelector('#subject');
input.value = room;
});
document.addEventListener('DOMContentLoaded', () => {
var room = localStorage.getItem('booking2');
var input = document.querySelector('#subject');
input.value = room;
});
But now, there's a new problem. I'm able to run the first product value to the enquiry.html page but when after i edited the second product codes, when i try to click back to the button on product.html for the first product, the second value still remains.
I have an input with attached datalist:
<input type="text" list="mylist">
<datalist id="mylist">
<option>1
<option>2
</datalist>
When I choose an option from the list then the change event doesn't fire on the input element. So how can I detect input's change?
You can capture the input event:
document.querySelector('input').addEventListener('input', function() {
alert('Changed!');
});
<input type="text" list="mylist">
<datalist id="mylist">
<option>1
<option>2
</datalist>
Update
I didn't notice the jQuery tag at first, and #YanickRochon made a good point that this should also capture the change event.
New Snippet
$('input').on('input change', function() {
alert('Changed!');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" list="mylist">
<datalist id="mylist">
<option>1
<option>2
</datalist>
$(document).ready(function(){
$('input').on('input', function () {
alert("changed");
})
});
Fiddle
You can use input event, like this
$('#input-list').on('input change', function () {
console.log($(this).val());
})
Example
All other answers are not differentiating between input scenarios
The question is about how to specifically know when an input was changed by a datalist and not by anything else. This is very important to differentiate.
The below code will absolutely differentiate between a user input either by typing, pasting via the keyboard or via mouse or any other way, and between actually selecting an option from a <datalist>
var noneDatalistInput;
$('input').on('keydown paste', onNoneDatalistInput)
.on('input', onInput);
// raise a flag
function onNoneDatalistInput(e){
if( e.key == "Enter" ) return;
if( noneDatalistInput ) clearTimeout(noneDatalistInput);
noneDatalistInput = setTimeout(function(){ noneDatalistInput = null }, 50);
}
function onInput(){
var isDatalistInput = !noneDatalistInput;
console.log('was a datalist option selected? ', isDatalistInput);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" list="mylist">
<datalist id="mylist">
<option>1</option>
<option>2</option>
</datalist>
are you listening to INPUT change? or DataList Change?
// wont work
$("#myList").on('change', function () {
alert("yay!");
});
// fires yay! when change value (after focus out)
$("#myText").on('change', function () {
alert("yay!");
});
check out this fiddle
E.g. I have an HTML form:
<form role="search" method="get" id="searchform" action="" >
<!-- DIRECT SEARCH INPUT TO SEARCH STRING -->
<input type="text" value="" name="s" id="s" />
<input type="submit" id="searchsubmit" value="Search" />
<!-- DROPDOWN TO SELECT ONE CHOICE -->
<select name='country' id='country' class='postform' >
<option class="level-0" value="2">USA</option>
<option class="level-0" value="3">Canada</option>
<option class="level-0" value="4">Mexico</option>
<option class="level-0" value="5">Cuba</option>
</select>
<!-- CHECKBOXES TO SELECT MULTIPLE CHOICES -->
<div id="color">
<input type="checkbox" name="" value="21" />Beachfront
<input type="checkbox" name="" value="16" />TV
<input type="checkbox" name="" value="20" />Internet
<input type="checkbox" name="" value="17" />Pets Allowed
</div>
</form>
<div id="results"><!-- THE AJAX RESULTS GOES HERE --></div>
And I want to be able to make AJAX request every time the user:
1) write something in the search input box and click search button
OR
2) select one choice from the dropdown menu
OR
3) select one or multiple choices from the checkboxes that are checked
The problem is that I don't know how to structure my JavaScript code correctly and what is the best way to remember and manage choices that the user selected before, to take all things in account. For example, not just the search term when he write something and click search button, but also to take in count the dropdown choice (probably done one step before) and maybe the checked options from checkboxes if he has checked something before. Here is what I have so far:
jQuery(document).ready(function($){
// RESULTS SHOULD APPEAR IN #results DIV AFTER AJAX IS DONE
var $maincontent = $('#results');
// SEARCH INPUT PROCESSING
$('#searchsubmit').click(function(e){
e.preventDefault();
var searchval = $('#s').val();
$.post(
WPaAjax.ajaxurl,
{
action : 'ajax_search_action_do',
searchval : searchval
},
function( response ) {
$maincontent.empty();
$maincontent.append( response );
}
);
});
// COUNTRY DROPDOWN CHOICE PROCESSING
$('#country').on('change', function() {
var countryval = this.value;
$maincontent.animate({ opacity : '0.1' })
$.post(
WPaAjax.ajaxurl,
{
action : 'ajax_search_action_do',
countryval : countryval
},
function( response ) {
$maincontent.empty();
$maincontent.append( response );
$maincontent.animate({ opacity : '1' })
}
);
return false;
});
// CHECKBOXES PROCESSING
$('#color input[type=checkbox]').click(function() {
if (this.checked) {
// code if checked
}
else {
// nothing
}
});
});
As you can see, it's very bad. Because one "function" checks only click, one change and I don't know how to grab values from the checkboxes and make an array and send it via ajax ;(.
Any idea how to structure the JavaScript code so it is not so separated and the checks are somehow in one part (or more logical) instead of three separated parts?
Any ideas are welcome.
Create som logic :
var _do = {
bind: function() {
var self = this;
$('#searchsubmit').on('click', function(e){
e.preventDefault();
self.ajax('searchval', $('#s').val());
});
$('#country').on('change', function() {
self.ajax('countryval', this.value);
});
return self;
},
ajax: function(key, value) {
var data = {action: 'ajax_search_action_do'};
data[key] = value;
$.post(
WPaAjax.ajaxurl, data, function( response ) {
$maincontent.empty().append( response );
}
);
}
}
jQuery(document).ready(function($){
_do.bind();
});
Maybe use jquery.form.js?
http://malsup.com/jquery/form/
It's a great plugin, just structure the form like it was a normal redirection form, add array in name of checkboxes
<input type="checkbox" name="types[]" value="21" />Beachfront
Add target URL to the form, and then...
When u want to submit the form just do
$('searchform').ajaxSubmit({
success: function() {
// callback
}
)
Trigger this on checkboxes change, dropdown change etc. To make the code clean, use one selector
$('#country, #s, #color input').on('change', sendAjaxForm);
Im trying to make a dynamic select menu where you select a customer and then filter the contacts for that customer.
when i select a customer it properly filters the contacts but the customer select menu does not show that anything is selected.
<template name="newLeadForm">
<form id="lead">
<fieldset>
<legend>New Lead</legend>
<br/>
<select id="customer_id" class="span12">
<option id="null" value="null">Select One</option>
{{#each customers}}<option id="{{id}}" value="{{_id}}">{{name}} - {{city}}, {{state}} {{zip}}</option>{{/each}}
</select>
<select id="contact_id" class="span12">
<option id="null" value="null">Select One</option>
{{#each contacts}}<option id="{{id}}" value="{{_id}}">{{first_name}} {{last_name}}</option>{{/each}}
</select>
<input id="submit" type="submit" class="btn">
</fieldset>
</form>
</template>
Here is the data being supplied to the template
Template.newLeadForm.customers = function () {
return Customers.find();
};
Template.newLeadForm.contacts = function () {
console.log(Session.get("_customer_id"));
return Contacts.find({customer_id: Session.get("_customer_id")});
};
and the event handlers
Template.insert.events({
'change form#lead #customer_id' : function (event) {
customer = $("form#lead #customer_id").val();
Session.set("_customer_id", $("form#lead #customer_id").val());
},
'submit form#lead' : function (event) {
if (event.type === 'click' || event.type === 'submit') {
event.preventDefault();
var customer_id = $("#customer_id").val();
var contact_id = $("#contact_id").val();
var lead_source_id = $("#lead_source_id").val();
var lead_number = $("#lead_number").val();
if(Leads.insert({id: Leads.find().count() + 1, customer_id: customer_id, contact_id: contact_id})) {
$("#customer_id").val(null);
$("#contact_id").val(null);
Session.set("_customer_id", null);
}
}
}
});
After Meteor re-renders the option elements in your select element, you should tell it to set the selectedIndex property on the select element so that it updates. You can do this with the rendered event:
Template.newLeadForm.rendered = function() {
$("#customer_id")[0].selectedIndex = 5; // possibly track the index so you know what to set it to
}
Simple workaround:
Template.newLeadForm.rendered = function(){
$('#customer_id').val(Session.get("_customer_id"))
}
Since newLeadForm depends on Session["_customer_id"], it will be re-rendered whenever Session["syntax"] changes, and thus template.hello.rendered will be called every time Session["syntax"] changes.
Another option, you can add an autorun for each select you want to keep updated:
if (Meteor.isClient){
Meteor.startup(function() {
Deps.autorun(keep_cust_select_updated)
})
function keep_cust_select_updated(){
$('#customer_id').val(Session.get("_customer_id"))
}
}
Whenever the Session.set("_customer_id", xxxx) is called, keep_select_updated will be rerun (as it is dependent on Session.get("_customer_id")) and the correct value will be selected (by the jQuery $('#customer_id').val(...) call).
The advantage of the latter method is you don't need to bother adding "selected" correctly into the html for each <option>
First of all thanks to the guys of backbone-forms who made a tool which perfectly integrates in the backbone.js framework.
I'm using backbone.js with the backbone-forms plugin, but I need to make conditional fields.
Let's say I've the following form.
I want to show (or not) a single line input with thext or a textarea according to the value selected in the select.
<form method="post" action="">
<select >
<option value="" selected="selected">choose one</option>
<option value="1" >line</option>
<option value="2" >area</option>
</select>
<input id="element_1" />
<textarea id="element_2" ></textarea>
</form>
A behaviour like this one is implemented by default in backbone?
If not, how can I implement it with javascript and backone-forms?
thanks.
You can bind events to the select element and have them toggle the visibility of other form elements.
Try this:
$(function() {
//The form
var form = new Backbone.Form({
schema: {
inputType: { type: 'Select', options: ['line', 'area'] },
line: 'Text',
area: 'TextArea'
}
}).render();
form.fields['area'].$el.hide();
form.on('inputType:change', function(form, editor) {
form.fields['line'].$el.toggle();
form.fields['area'].$el.toggle();
});
//Add it to the page
$('body').append(form.el);
});
Here's some live code: http://jsfiddle.net/shioyama/grn6y/
Derived from this: https://groups.google.com/d/topic/backbone-forms/X5eVdTZWluQ/discussion
There is no default implementation.In fact, completely on your own is also very simple, please reference the following code:
//Pseudo code
var line = $("element_1"),area = $("element_2");
if(selectvalue ==="1"){
line.show();
area.hide();
}
else{
line.hide();
area.show();
}