.remove(":contains()") not working - jquery-selectors

I have a input field where value is equal to the id's and a button. When that button is triggered I want to remove the id in the input field also the button where the value is equal to the data stored in the input field or the id. Here http://jsfiddle.net/leonardeveloper/hcfzL/3/
HTML:
<form id="materialForm" action="#" method="post">
<input id="materials" type="text" name="materials" value="1,2,3" readonly="readonly" disabled="disabled" />
</form>
<div id="display">
<button class="removes" value="1">x</button>
<button class="removes" value="2">x</button>
<button class="removes" value="3">x</button>
</div>
JS:
$(document).on('click', '.removes', function () {
var id = $(this).val();
alert(id);
$('#materials').remove(":contains('" + id + "')");
$('#display').remove(":contains('" + id + "')");
return false;
});

.remove() is for removing DOM elements, not text from values. And it removes the element it's applied to, not elements that are contained within it.
$(document).on('click', '.removes', function () {
var id = $(this).val();
alert(id);
var materials = $('#materials').val().split(',');
materials = materials.filter(function(e) {
return e != id;
});
$('#materials').val(materials.join(','));
$(this).remove();
return false;
});
FIDDLE

The :contains selector is for selecting DOM nodes that contain other DOM nodes. In your case you look to be selecting input elements which have a particular string in their value.
You should probably use .filter to filter to select the input elements that match the filter.

Try
$(document).on('click','.removes',function(){
var id = $(this).val();
$('#materials').val(function(){
var value = this.value, array = value.split(',');
var idx = $.inArray(id, array);
if(idx >=0 ){
array.splice(idx, 1)
value = array.join(',')
}
return value;
})
$(this).remove();
return false;
});
Demo: Fiddle

Related

How to access newly created DOM elements in JS? (I have used appendChild)

I am making a to do list. Each list item includes a remove button when created.
But I cannot access these remove buttons in my script, because it is not included in my DOM, although I used '.appendChild'. Can anyone help?
const buttonSubmit = document.querySelector('#button-submit');
const form = document.querySelector('form');
const icons = document.querySelector('#icons');
let toDoList = document.querySelector('#todolist');
const input = document.querySelector('#formtext');
form.addEventListener('submit', (e) => {
e.preventDefault();
const newListItem = document.createElement('li');
newListItem.innerHTML = '<span>' + input.value + '</span>' +
'<span id="icons">' +
'<button id="check" class="buttonlist">' + '<img src="checked.png" alt="">' + '</button>' +
'<button id="remove" class="buttonlist">' + '<img src="remove.png" alt="">' + '</button>' +
'<button id="edit" class="buttonlist">' + '<img src="edit.png" alt="">' + '</button>' + '</span>';
toDoList.appendChild(newListItem);
form.reset();
})
const buttonCheck = document.querySelector('#check');
const buttonEdit = document.querySelector('#edit');
const buttonRemove = document.getElementById('remove');
buttonRemove.addEventListener('click', function() {
alert('remove list item');
})
<div class="container-box">
<h1>To Do List</h1>
<br>
<form action="">
<input type="text" id="formtext" name="formtext">
<button id="button-submit">Add Item</button>
</form>
<br><br><br><br>
<!-- Dynamic list here -->
<ul id="todolist"> </ul>
</div>
Problems
ids must be unique, every time you add a task to the list -- after the first one everything is invalid HTML. When directed to an id the browser will find the first id then stop and ignore the duplicate ids. Use class and/or name attributes for any replicated tags.
The reason why the remove button doesn't work is because the reference to the button was defined when it didn't exist.
Figure I
// After page is loaded...
const buttonRemove = document.getElementById('remove');
// Console will tell you buttonRemove is null
// User has not entered any data nor has user clicked the add button
Moreover, even if that was fixed by referencing the button after it was created, binding it as shown on Figure II will only work for the first button only.
Figure II
buttonRemove.addEventListener('click', function() {
alert('remove list item'); // Don't use alert() use console.log()
})
Solution
Reference tags after they are created. In the OP (Original Post), the contents of the <li> is rendered htmlString which makes referencing newly created tags problematic plus binding to dynamically created tags individually should be avoided if it's feasible and practical in which in most cases it is.
To handle events for an unknown amount of dynamically created tags, bind the event to a static ancestor tag, which in the OP is <ul> or any of it's parent tags (even <body>, document, and window but it's best to be as close as possible). Then make it so the event handler controls which tags respond and how. See Appendix located at the very end of this answer for more details.
There are two examples:
Example A - revised OP code
Example B - a todo list using HTMLFormElement interface, see Appendix
Both examples have commented step-by-step details
Example A
// Reference <form>, <ul>, and <input>
const form = document.querySelector('form');
const list = document.querySelector('ul');
const input = document.querySelector('#text');
// Bind <form> to submit event
form.addEventListener('submit', (e) => {
// Stop default behavior of <form> during submit ecent
e.preventDefault();
// Create <li> and <output>
const item = document.createElement('li');
const out = document.createElement('output');
// Assign value of <input> to the value of <output>
out.value = input.value;
// Add <output> to <li> -- <li> to <ul>
item.append(out);
list.append(item);
/*
Run a for loop 3 times -- on each iteration...
...create an <input> and assign type as "button"...
...buttons [name] and [value] is determined by current index...
...add button to <li>
*/
for (let i = 0; i < 3; i++) {
let btn = document.createElement('input');
btn.type = 'button';
let cmd = i === 0 ? 'done' : i === 1 ? 'edit' : i === 2 ? 'remove' : false;
btn.name = cmd;
btn.value = cmd;
item.append(btn);
}
// Reset <form>
form.reset();
});
// Bind <ul> to click event
list.addEventListener('click', manageList);
// Event handler always passes event object by default
function manageList(e) {
// Reference the tag user clicked
const clk = e.target;
// If user clicked a remove button remove it's parent tag
if (clk.name === 'remove') {
clk.parentElement.remove();
}
if (clk.name === 'edit') {
console.log('EDIT');
}
if (clk.name === 'done') {
console.log('DONE');
}
}
li {
display: flex;
align-items: center
}
[type='button'] {
text-transform: capitalize
}
<form>
<input id="text" name="text" type="text">
<button>Add Item</button>
</form>
<br>
<ul></ul>
Example B
// Bind <form> to click event
document.forms.todo.onclick = taskList;
// Event handler akways passes the event object
function taskList(e) {
// Reference the tag user clicked
const clk = e.target;
// Reference all form controls
const IO = this.elements;
/*
If the user clicked the add button...
...reference the <ul>...
...create <li> and <output>...
...add text from <input> to <output>...
...add <output> to <li>...
...Run a for loop 3 times -- on each iteration...
...create an <button> and assign type as "button"...
...buttons [name] and text is determined by current index...
...add button to <li>...
...add <li> to <ul>...
...clear <input>
*/
if (clk.name == 'add') {
const list = IO.list.firstElementChild;
const item = document.createElement('li');
const text = document.createElement('output');
text.value = IO.data.value;
item.append(text);
for (let i = 0; i < 3; i++) {
let btn = document.createElement('button');
btn.type = 'button';
let cmd = i === 0 ? 'done' : i === 1 ? 'edit' : i === 2 ? 'remove' : false;
btn.name = cmd;
btn.textContent = cmd;
item.append(btn);
}
list.append(item);
IO.data.value = '';
}
/*
If the user clicked a remove button...
...find the <li> ancestor of remove button and remove
it thereby removing the <output> and itself as well
*/
if (clk.name === 'remove') {
clk.closest('li').remove();
}
if (clk.name === 'done') {
console.log('DONE');
}
if (clk.name === 'edit') {
console.log('EDIT');
}
}
<form id='todo'>
<input id='data' required><button name='add' type='button'>Add</button>
<fieldset id='list'>
<ul></ul>
</fieldset>
</form>
Appendix
Events
Event delegation
HTMLFormElement
HTMLFormControlsCollection
Form Controls

How to pass UTM info to form submit?

Bottom line, I want to know exactly which leads (form submissions) came through Adwords.
It's a manually built form (no JotForm or anything) and submits through manually built php that, at the moment) sends me an Email. The page and form itself is HTML.
So we can add UTM info to the Adwords URLs, and I'm looking for a way to grab that UTM information and pass it on to the Email (like through a hidden field in the form or something.)
I think this would be the easiest way to make sure we know which leads we paid for, but if not, please let me know of a better way.
TIA
The best way to track these utm is to store them into a js cookie and then retrieve them to store values into hidden fields in form.
using cookies will allow you to navigate through different pages without having to pass the data again and again in the url.
You can modify this solution to use for your form.
http://www.decorumsol.com/tracking-utm-parameters-in-contact-form-7/
Edit:
Here is the code for better understanding.
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
jQuery(document).ready(function() {
jQuery('form').find('input.utm_source').each(function() {
var a = getQueryVariable('utm_source');
if(a){
jQuery(this).val(a);
}
});
jQuery('form').find('input.utm_medium').each(function() {
var a = getQueryVariable('utm_medium');
if(a){
jQuery(this).val(a);
}
});
jQuery('form').find('input.utm_campaign').each(function() {
var a = getQueryVariable('utm_campaign');
if(a){
jQuery(this).val(a);
}
});
jQuery('form').find('input.utm_term').each(function() {
var a = getQueryVariable('utm_term');
if(a){
jQuery(this).val(a);
}
});
jQuery('form').find('input.utm_content').each(function() {
var a = getQueryVariable('utm_content');
if(a){
jQuery(this).val(a);
}
});
});
function createCookie(name,value,days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name) {
createCookie(name,"",-1);
}
var c_name = "_aaa_utmz";
if(getQueryVariable("utm_source") != "") {
createCookie("_aaa_utmz", getQueryVariable("utm_source") + "|" + getQueryVariable("utm_medium")+ "|" + getQueryVariable("utm_term")+ "|" + getQueryVariable("utm_campaign")+ "|" + getQueryVariable("utm_content"), 60);
}
else if (readCookie(c_name)){
c_start=readCookie(c_name);
var _pipe = c_start.split("|");
jQuery("input[name=utm_source], .utm_source").val(_pipe[0]);
jQuery("input[name=utm_medium], .utm_medium").val(_pipe[1]);
jQuery("input[name=utm_term], .utm_term").val(_pipe[2]);
jQuery("input[name=utm_campaign], .utm_campaign").val(_pipe[3]);
jQuery("input[name=utm_content], .utm_content").val(_pipe[4]);
}
in your html form, create
<div style="display:none;">
<input type="text" value="" class="utm_source" name="utm_source" />
<input type="text" value="" class="utm_medium" name="utm_medium" />
<input type="text" value="" class="utm_term" name="utm_term" />
<input type="text" value="" class="utm_campaign" name="utm_campaign" />
<input type="text" value="" class="utm_content" name="utm_content" />
</div>

kendo bind HTML elements to grid selected row/dataItem

I have the following situation (using KendoUI):
I have a grid binded to a datasource.
When I select a row in the grid I invoke its "change" event to get the selected dataItem e show its values through other HTML elements.
Something like the following:
$("grid-element").kendoGrid({
change: setElements
});
function setElements() {
var grid = $("#grid-element").data("kendoGrid");
var selectedItem = grid.dataItem(grid.select());
$("#span-field1").text(selectedItem.field1);
$("#span-field2").text(selectedItem.field2);
$("#span-field3").text(selectedItem.field3);
}
My question is: is it possibile to achieve the same through MVVM or a better KendoUI model binding solution?
So far I have found the following solution:
=== JAVASCRIPT ===
var vm = kendo.observable({
gridSelectedItem: null,
_field1: function() {
return this.get("gridSelectedItem.field1");
},
_field2: function() {
return this.get("gridSelectedItem.field2");
}
});
$("#grid-element").kendoGrid({
change: function(e) {
var selectedItem = this.dataItem(this.select());
vm.set("gridSelectedItem", selectedItem);
}
});
=== HTML ===
<span data-bind="text: _field1"></span>
<span data-bind="text: _field2"></span>
Is there a better way?
Indeed there you are on the right track,
Here is what I can suggest you to try:
=== JAVASCRIPT ===
var vm = kendo.observable({
gridSelectedItem: null
});
$("#grid-element").kendoGrid({
change: function(e) {
var selectedItem = this.dataItem(this.select());
vm.set("gridSelectedItem", selectedItem);
}
});
=== HTML ===
<span data-bind="text: gridSelectedItem.field1"></span>
<span data-bind="text: gridSelectedItem.field2"></span>
It should be slightly more compact.

Incrementing value (integer) in an input type field

I have input text and I want to increase the number that is inside using the key up or down.
I have:
<input type="text" value="1" name="qty" />
After digging stackoverflow I found: Is it possible to handle up/down key in HTML input field?
The solution is to use: Keycodes 37 - 40 should do it for you. They map as 37=left, 38=up, 39=right, 40=down.
But How can I use these code in my form? Is there a Javascript function that do this (like : increase() or decrease()?
Thanks
You could do something like this, using the "onkeydown" event.
<script type="text/javascript">
function increment(e,field) {
var keynum
if(window.event) {// IE
keynum = e.keyCode
} else if(e.which) {// Netscape/Firefox/Opera
keynum = e.which
}
if (keynum == 38) {
field.value = parseInt(field.value)+ 1;
} else if (keynum == 40) {
field.value = parseInt(field.value) - 1;
}
return false;
}
</script>
<input type="text" onkeydown="increment(event, this)" value="10">

Jquery retrieve values of Dynamically created elements

I have a html page with a form.
The form has Div which gets populated dynamically with Input elements like text box,radio,checkbox etc.
Now I want to retrieve the values of these dynamically created elements in the Html page,so that i can submit it to a page.
//HTML PAGE
<script type="text/javascript">
$(function() {
populateQuestions();
});
$("#submit_btn").click(function() {
// validate and process form here
//HOW TO ??retrieve values???
var optionSelected = $("input#OptionSelected_1").val();// doesn't work?
// alert(optionSelected);
postAnswer(qid,values);//submit values
showNextQuestion() ;// populate Div Questions again new values
});
</script>
<form action="" name="frmQuestion">
<div id="Questions" style="color: #FF0000">
</div>
//Question DIV generation script example radio buttons
//questionText text of question
//option for question questionOptions
// **sample call**
var question = createQuestionElement("1","MCQ", "WHAT IS ABCD??", "Opt1$Opt2$Opt3");
question.appendTo($('#Questions'));
function createQuestionElement(id, type, questionText, questionOptions) {
var questionDiv = $('<div>').attr('id', 'Question');
var divTitle = $('<div>').attr('id', 'Question Title').html(questionText);
divTitle.appendTo(questionDiv);
var divOptions = $('<div>').attr('id', 'Question Options');
createOptions(id, "radio", questionOptions, divOptions);
divOptions.appendTo(questionDiv);
return questionDiv;
}
function createOptions(id, type, options, div) {
var optionArray = options.split("$");
// Loop over each value in the array.
$.each(
optionArray, function(intIndex, objValue) {
if (intIndex == 0) {
div.append($("<input type='" + type + "' name='OptionSelected_" + id + "' checked='checked' value='" + objValue + "'>"));
} else {
div.append($("<input type='" + type + "' name='OptionSelected_" + id + "' value='" + objValue + "'>"));
}
div.append(objValue);
div.append("<br/>");
}
You are creating the same input multiple times, since you're splitting the option array, you're making this:
<input type='radio' name='OptionSelected_1' checked='checked' value='Opt1'>
<input type='radio' name='OptionSelected_1' value='Opt2'>
<input type='radio' name='OptionSelected_1' value='Opt3'>
You are currently fetching by ID with the #, instead you want to fetch by name and get the :checked item, like this:
var optionSelected = $("input[name=OptionSelected_1]:checked").val();