I want to put an empty select on an html page.
When the users clicks on this select, I want to load items from a web service.
I did manage to make it work with a bootstrap button but not with a basic html select.
There is very little information to go on from your question... But generally you could use an AJAX call to dynamically fill in the options.
$("select").click(function(){
$.getJSON(url, function(data){
options = JSON.parse(data);
$.each(options, function(index, value){
$("<option/>").appendTo("select").val(value).append(value);
});
});
});
This is a very similar solution to the one CodeAt30 suggested, but without the jQuery dependency:
// fake web service
const getSelectOptions = () => new Promise((resolve, reject) => {
resolve(['option 1','option 2', 'option 3', 'option 4']);
});
const populateWithOptions = () => {
//abort if select box has already been populated
if(document.querySelector('#s1 option')) return;
const selectElement = document.querySelector('#s1');
getSelectOptions().then(options => {
options.forEach(option => {
const optionElement = document.createElement('option');
optionElement.value = option;
optionElement.innerHTML = option;
selectElement.appendChild(optionElement);
}
);
});
};
const handleSelect = () => {
const selectElement = document.querySelector('#s1');
alert('user selected ' + selectElement.value);
}
window.populateWithOptions = populateWithOptions;
window.handleSelect = handleSelect;
<div>
<select id="s1" onmouseover="populateWithOptions()" onclick="populateWithOptions()" onchange="handleSelect()">
</select>
</div>
Related
I would like the user to be able to record an action that they have carried out. I grouped the actions by category and then using two select menus and JS the user is only showed the actions from the category that they have selected. There is also a quantity input that is generated depending on which action is selected.
My issue is that when I submit the form, I get the error:
Uncaught TypeError: Cannot set property 'onchange' of null
The select box and the functionality implemented by the JS work until the form is submitted.
index.js
document.addEventListener("DOMContentLoaded", () => {
// First select
let cat_select = document.getElementById("id_post_cat");
cat_select.onchange = () => handleCatChange(cat_select.value);
// Second select
let desc_select = document.getElementById("id_post_action");
desc_select.onchange = () => handleDescChange(desc_select.value);
});
const handleCatChange = (cat) => {
let quantity_div = document.getElementById("quantity_div");
quantity_div.innerHTML = "";
// Fetching the actions in the category selected and populating second select
fetch(`/action/${cat}`)
.then((response) => response.json())
.then((data) => {
let desc_select = document.getElementById("id_post_action");
let optionHTML = "<option>---------</option>";
data.actions.forEach((action) => {
optionHTML +=
'<option value"' + action.id + '">' + action.desc + "</option>";
});
desc_select.innerHTML = optionHTML;
})
.catch((err) => console.log(err));
};
const handleDescChange = (desc) => {
let quantity_div = document.getElementById("quantity_div");
quantity_div.innerHTML = "";
let time_actions = [
"Public transport instead of driving",
"Walk/cycle instead of drive",
];
let quant_actions = [
"Unplug unused electrical items",
"Repurpose a waste object",
"Use a reusable bag",
"Buy an unpackaged item",
"Buy a locally produced item",
"Buy a second hand item",
"Buy an object in bulk",
"Use a refillable bottle/to-go mug",
"Drink a tap beer instead of bottled beer",
];
if (time_actions.includes(desc)) {
formAdder("Distance* (km)");
} else if (quant_actions.includes(desc)) {
formAdder("Quantity*");
}
};
const formAdder = (label_content) => {
let quantity_div = document.getElementById("quantity_div");
// Label
let label = document.createElement("label");
label.innerHTML = `${label_content}`;
label.setAttribute("for", "id_post_quantity");
label.classList += "requiredField";
// Input
let input = document.createElement("input");
input.setAttribute("id", "id_post_quantity");
input.setAttribute("name", "post_quantity");
input.setAttribute("required", "");
input.classList += "form-control";
quantity_div.append(label, input);
};
views.py
#login_required
def record(request):
if request.method == 'POST':
form = NewPostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.poster = request.user
if request.POST.get('id_post_quantity'):
post.post_quantity = request.POST.get('id_post_quantity')
post.save()
return HttpResponseRedirect(reverse('index'))
return render(request, 'my_app/record.html', {
'form': NewPostForm
})
record.html
<form action="{% url 'record' %}" method="post">
{% csrf_token %}
{{form.post_cat|as_crispy_field}}
{{form.post_action|as_crispy_field}}
<div class="form-group" id="quantity_div">
</div>
<button class="btn btn-success" type="submit">Post</button>
</form>
A pointer in the right direction would be greatly appreciated thank you.
It seems the onchange was being called on every page that was loaded. That meant that, when redirecting to the index page (where the select boxes don't exist), the getElementById was returning a null value etc.
I changed this by adding conditionals to check if the elements are present on the page:
document.addEventListener("DOMContentLoaded", () => {
// First select
let cat_select = document.getElementById("id_post_cat");
if (!!cat_select) {
cat_select.onchange = () => handleCatChange(cat_select.value);
}
// Second select
let desc_select = document.getElementById("id_post_action");
if (!!desc_select) {
desc_select.onchange = () => handleDescChange(desc_select.value);
}
});
Is there a more elegant/correct way of solving the same problem?
for me it got fixed when i changed on submit event to btn click event.
I have a little problem with my html form code...
In my code, there are few input fields which are generated dynamically. In every input field generated dynamically, there is some numerical value. i need to do some Mathematical calculation with them.
="PE+ROCE+(2-SG)-(4-DY/2)"
This is a pattern of my calculation. In this, PE, ROCE etc are the IDs of Dynamic Input fields generated.
Using values of dynamic input fields generated, I need to perform above calculation.
This calculation has to be executed when the user would click on "Calculate" Input Button.
Then, the final calculated value from the above will be shown in the Output Tag present in bottom of my form code.
I tried to solve this problem on my own. But unfortunately, failed in this task.
somebody can now please help me to solve this problem.
I will be very grateful...
here is my full code of form..
// define the headings here, so we can access it globally
// in the app
let headings = []
// appending the created HTML string to the DOM
function initInputs(headingList) {
jQuery(".fields").append(createInputsHTML(headingList))
}
// the HTMLT template that is going to be appended
// to the DOM
function createInputsHTML(headingList) {
let html = ''
headingList.forEach(heading => {
if (heading !== 'Company') {
html += `<label for="${heading}">${heading}: </label>`
html += `<input id="${heading}">`
html += '<br>'
}
})
return html
}
// receiving data
// this data arrives later in the app's lifecycle,
// so it's the best to return a Promise object
// that gets resolved (check JS Promise for more information)
function getJSON() {
return new Promise(resolve => {
jQuery.get("https://cors-anywhere.herokuapp.com/www.coasilat.com/wp-content/uploads/2019/06/data-1.txt", function(data) {
resolve(JSON.parse(data))
});
})
}
// processing raw JSON data
function processRawData(data) {
return new Promise(resolve => {
const companyData = []
// creating data array
// handling multiple sheets
Object.values(data).forEach((sheet, index) => {
sheet.forEach((company, i) => {
companyData.push({ ...company
})
// create headings only once
if (index === 0 && i === 0) {
Object.keys(company).forEach(item => {
headings.push(item.trim())
})
}
})
})
resolve(companyData)
})
}
$(async function() {
let lists = [];
function initAutocomplete(list) {
const thisKey = 'Company'
$("#company").autocomplete('option', 'source', function(request, response) {
response(
list.filter(item => {
if (item[thisKey].toLowerCase().includes(request.term.toLowerCase())) {
item.label = item[thisKey]
return item
}
})
)
})
}
$("#company").autocomplete({
minLength: 3,
source: lists,
focus: function(event, ui) {
// the "species" is constant - it shouldn't be modified
$("#company").val(ui.item.Company);
return false;
},
select: function(event, ui) {
// handling n number of fields / columns
headings.forEach(heading => {
$('#' + heading).val(ui.item[heading])
})
return false;
}
});
// starting data download, processing and usage
getJSON()
.then(json => {
return processRawData(json)
})
.then(data => {
// just so we see what data we are using
console.log(data)
// make the processed data accessible globally
lists = data
initAutocomplete(lists)
initInputs(headings)
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
<div class="ui-widget">
<form id="frm1">
<label for="company">Company: </label>
<input id="company"><br />
<div class="fields"></div>
<input type="submit" id="calculate" value="Calculate">
<p>Final Amount <output name="amount" for="calculation">0</output></p>
</form>
</div>
Try each loop of inputs
$("#Calculate").click(function(){
var peVal,roceVal,sgVal,dyVal;
jQuery(".fields input").each(function (){
var idHeading=$(this).attr("id");
if(idHeading=="Your ID for PE input"){
peVal=parseInt($(this).val());
}
if(idHeading=="Your ID for ROCE input "){
roceVal=parseInt($(this).val());
}
if(idHeading=="Your ID for SG input"){
sgVal=parseInt($(this).val());
}
if(idHeading=="Your ID for DY input"){
dyVal=parseInt($(this).val());
}
});
var output=peVal+roceVal+(2-sgVal)-(4-dyVal/2);
});
So I am trying to make an edit function for a favorites bar. Editing one box is okay, but when I try to edit a different box, all the boxes that I clicked on previously gets edited as well. Here is a jsfiddle with the complete code: https://jsfiddle.net/1exrf9h8/1/
I am trying to understand why my editFavorite function is updating multiple boxes and not just one.
function clickEdit(input, title, url, plus, editIcon, anchorEdit, editBtn)
{
let i = editIcon.length - 1;
editIcon[i].addEventListener("click", function(event){
input.style.display = "block";
title.value = plus[i + 1].textContent;
url.value = anchorEdit[i].href;
console.log(i);
console.log(anchorEdit[i]);
editFavorite(anchorEdit[i], url, title, input, editBtn);
});
}
function editFavorite(changed, url, title, input, editBtn)
{
editBtn.addEventListener("click", function(){
changed.href = url.value;
changed.textContent = title.value;
input.style.display = "none";
});
}
There is a few problems in your logic, architecture and use of the event handler, Let's give it a shot in a more OOP way so you can actually make it to work and understand what is going on.
Every single favorite is an object by itself, that can spawn and update itself.
function favorite(newTitle, newUrl) {
this.element = container.appendChild(document.createElement("div"));
this.title = this.element.appendChild(document.createElement("h2"));
this.url = this.element.appendChild(document.createElement("h2"));
this.update = (newTitle, newUrl) => {
this.title.textContent = newTitle;
this.url.textContent = newUrl;
}
this.createButton = () => {
button = this.element.appendChild(document.createElement("button"));
button.append("Edit");
button.addEventListener("click", () => {
let titleInput = document.getElementById("title").value;
let urlInput = document.getElementById("url").value;
this.update(titleInput, urlInput);
})
}
this.update(newTitle, newUrl);
this.createButton();
}
Then let's have a simple form where we can take inputs, using the same for editing, and creating a new favorites.
<input id="title" type="text" name="title" placeholder="Title">
<input id="url" type="text" name="url" placeholder="Url">
<button id="submit">Create New</button>
Now the actual submit logic.
document.getElementById("submit").addEventListener("click", () => {
let titleInput = document.getElementById("title").value;
let urlInput = document.getElementById("url").value;
if (!titleInput.length || !urlInput.length) return;
let newFavorite = new favorite(titleInput, urlInput);
container.appendChild(newFavorite.element);
});
https://jsfiddle.net/p50L27us/48/
The problem is caused by editFavorite function. when you call editFavorite function automatically starts new listener. Evey click start new one.
The solution is " ,{once : true} "
function editFavorite(changed, url, title, input, editBtn)
{
editBtn.addEventListener("click", function(){
changed.href = url.value;
changed.textContent = title.value;
input.style.display = "none";
},{once : true});
}
I have just come across SumoSelect.js for dropdowns in my MVC project.
I just wanted to know if there is way to know if the select all option of the sumoselect dropdown is checked or not.
This is my sumoslect drop down code.
<div>
#Html.LabelFor(m => m.Territory)
#Html.DropDownListFor(m => m.Territory, Model.Territories, new { #class = "form-control", id = "ddlTerritory", multiple = "multiple", placeholder = "Select Territory" })
#Html.ValidationMessageFor(m => m.Territory)
</div>
JavaScript Code
$(document).ready(function ()
{
$('#ddlTerritory').SumoSelect({ selectAll: true });
if ($('#ddlTerritory')[0].sumo.selectAll())
{
some code
}
}
There is no mention of such method in the documentation of sumoselect.
It would be great if some one can guide me in the right direction.
Edit: As Suggested by #stephen
$(document).ready(function ()
{
$('#ddlTerritory').SumoSelect({ selectAll: true });
var isChecked = $('#ddlTerritory').closest('.SumoSelect').find('.select-all').hasClass('.select');
if (isChecked)
{
some code
}
}
this quite tricky, that I count selected items with total options:
function isMultipleSelectAll(id) {
var ids = $(id).val();
let options = $(id + " option");
let totalSelected = ids.length;
let totalOptions = options.length;
if (totalSelected >= totalOptions) {
return true;
} else {
return false;
}
}
I am having two dropdown (PrimarySpeciality,PrimarySubSpeciality), based on the value in one dropdown(PrimarySpeciality) the other dropdown(PrimarySubSpeciality) value should change.
On Load, I want the 'PrimarySubSpecialities' on load to default value.
How can i do it?
my cshtml:
<div class="nmc-righttab" style="width:265px;">
#Html.DropDownListFor(m => m.User.PSpecialty, Model.PSpecialties, new { id = "ddUserDetails", style = "width:245px;height:25px;", data_bind = "event: {change: primaryChanged}" }, Model.IsReadOnly)
</div>
<div style="width:265px;">
#Html.DropDownListFor(m => m.User.PSubSpecialty,Model.PSubspecialties, new { id = "ddUserDetailsPSubSpeciality", style = "width:245px;height:25px;", data_bind = "options: pSubSpecialities,optionsText: 'Name',optionsValue: 'Id',value:PSubspecialty,enable:isPSpecialitySelected" })
</div>
My JS File:
this.PSubspecialty = ko.observable($('#ddUserDetails').val());
this.pSubSpecialities = ko.observableArray([]);
this.isPSpecialitySelected = ko.observable(false);
this.pSpecilaityChanged = function () {
var pSpecialityVal = $("#ddUserDetails").val();
if (pSpecialityVal) {
model.isPSpecialitySelected(true);
pStartIndex = 0;
pSubSpecialityUrl = '/User/GetSpec?pSpeciality=' + pSpecialityVal +'&sSpeciality=';
loadPSubSpecilaities();
}
else
{
model.isSelected(false);
}
};
On Load,I want to set initial value for 'pSubSpeciality' to be text as '<>' with value as '0'.
Even I am able to add item to Model.PSubSpecialties,but could not be able to display the added item in psubspeciality dropdown.
How can set the initial value to pSubSpecialityDropdown from Model.PSubSpecialities.
Work within your model more, and with the UI less. Instead of making a changed event on the DropDownList items, subscribe to changes on a value-bound variable. In your PrimarySpecialty DropDown,
data_bind = "value: primarySpecialty"
Then in your JS:
var self = this;
this.primarySpecialty = ko.observable();
this.isPrimarySpecialtySelected = ko.pureComputed(function () {
return !!self.primarySpecialty();
});
this.primarySubSpeciality = ko.observable();
//...
this.primarySpecialty.subscribe(function (newValue) {
if (newValue) {
loadPrimarySubSpecialities();
this.primarySubSpeciality('0'); // Set default, by value
}
});
If the PrimarySubSpeciality dropdown has an option whose Id member is '0', the item will be selected in it.