jQuery search plugin (jSearch) searching more than one area - javascript

Hey all I am using the jQuery plugin called jSearch and I have the following code that currently allows me to search some tags within the said class name:
var jSearch = (function () {
var input = $('#searchTxtBox');
var items = $('#inventory .select3-multiple-selected-item');
input.keyup(function () {
var input = $(this).val();
switch (true) {
case input === '':
items.css('opacity', '1');
break;
default:
items.css('opacity', '0.2');
items.filter('[data-searchBox*="' + input.toLowerCase() + '"]').css('opacity', '1');
break;
}
});
}());
And some of the HTML:
<div class="cssMadeTbl-cell">
<label class="control-label" data-base="NEW_Project" data-definedas="text" data-required="True" for="inventory"></label>
<div style="float: right;">
<input class="tips" data-tooltip="example 1" id="searchTxtBox" name="searchTxtBox" placeholder="Search..." type="search" value=" ">
</div>
<div class="input-group">
<span data-db="bomStatus" class="bomClass" data-id="The Status">The Status</span>
<span id="lblBG"></span>
<div class="input-group-addon" style="width: 33px;">
<img src="data:image/svg+xml;base64,+DQo8L2c+DQo8L2c+DQo8L2c+Qo8L2c+DQo8L2c+DQo8L3N2Zz4NCg==" id="iconImg_currentUsers" style="width: 20px; height:20px;">
</div>
<div class="col-sm-10">
<span id="inventory" class="tips form-control input-sm" data_tooltip="example 1" data-cnt="0">
<div class="select3-multiple-input-container">
<span class="select3-multiple-selected-item" data-item-id="1" data-searchbox="pending">Pending</span>
<span class="select3-multiple-selected-item" data-item-id="2" data-searchbox="approved">Approved</span>
<span class="select3-multiple-selected-item" data-item-id="3" data-searchbox="denied">Denied</span>
<span class="select3-multiple-selected-item" data-item-id="ADDtab_100954500" data-searchbox="add item">ADD ITEM</span>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" class="select3-multiple-input" placeholder="">
<span class="select3-multiple-input select3-width-detector"></span>
<div class="clearfix"></div>
</div>
</span>
</div>
</div>
</div>
This works just fine for the above area. But the problem is that, on that same page, I have more InventoryXX id's that I am in need of adding the search box too as well. These range from Inventory to Inventory18.
I know I could do something like this:
var jSearch1 = (function () {
var input = $('#searchTxtBox');
var items = $('#inventory .select3-multiple-selected-item');
[more code here....]
var jSearch2 = (function () {
var input = $('#searchTxtBox');
var items = $('#inventory1 .select3-multiple-selected-item');
[more code here....]
var jSearch3 = (function () {
var input = $('#searchTxtBox');
var items = $('#inventory2 .select3-multiple-selected-item');
[more code here....]
[etc etc...]
But that would look really messy...
How can I modify this jQuery script in order to accommodate all those Inventory id's but still have each separate from each other?

Try to omit the #inventory:
var items = $('.select3-multiple-selected-item');
or modify the selector this way if you need to target #inventory* only:
var items = $('[id^="inventory"] .select3-multiple-selected-item');

Related

Counting characters during edit

I have a script that is used to count the number of characters in the input. It works well for the creation, but when it comes to the edit form the problem is that while displaying the old input it shows 0 and only starts counting when I'm starting to add some characters to the input. So I need it to display the number of characters of the old input even if I didn't add any new characters yet. How can I achieve that?
HTML code:
<input type="text" name="name" class="form-control" value="{{ $employee->name }}" placeholder="Name is..." id="myText">
<div class="d-flex justify-content-end">
<span id="wordCount" class="text-muted">0</span>
<span class="text-muted">/</span>
<span class="text-muted">256</span>
</div>
Script:
var myText = document.getElementById("myText");
var wordCount = document.getElementById("wordCount");
myText.addEventListener("keyup",function(){
var characters = myText.value.split('');
wordCount.innerText = characters.filter( item => {
return (item != ' ');
}).length;
});
var myText = document.getElementById("myText");
var wordCount = document.getElementById("wordCount");
const wordCounterHelper = () => {
var characters = myText.value.split('');
wordCount.innerText = characters.filter( item => {
return (item != ' ');
}).length;
}
wordCounterHelper()
myText.addEventListener("input", () => {wordCounterHelper()});
<input type="text" name="name" class="form-control" value="Funky Chicken" placeholder="Name is..." id="myText">
<div class="d-flex justify-content-end">
<span id="wordCount" class="text-muted">0</span>
<span class="text-muted">/</span>
<span class="text-muted">256</span>
</div>
Basically you need to run the code in the event listener once before, cause else it will only be executed once you begin typing in the edit form.
This is best done by putting the code into a function and the calling the function one separate time in the js.
Also I've changed the event to the input event as this fires on any value change of the input and not just keyup
Your code needs to be moved into a function so you can trigger it in multiple places. Also your code ignores paste events not done with the keyboard.
I kept word count there name there.... put you are counting letters, not words.
var myText = document.getElementById("myText");
var wordCount = document.getElementById("wordCount");
function setLetterCount() {
wordCount.innerText = myText.value.replace(/\s/g, '').length;
}
myText.addEventListener("input", setLetterCount);
setLetterCount();
<input type="text" name="name" class="form-control" value="Funky Chicken" placeholder="Name is..." id="myText">
<div class="d-flex justify-content-end">
<span id="wordCount" class="text-muted">0</span>
<span class="text-muted">/</span>
<span class="text-muted">256</span>
</div>
Other way is to trigger the event with dispatchEvent
var myText = document.getElementById("myText");
var wordCount = document.getElementById("wordCount");
myText.addEventListener("input", function() {
wordCount.innerText = myText.value.replace(/\s/g, '').length;
});
myText.dispatchEvent(new Event('input', {
bubbles: true
}));
<input type="text" name="name" class="form-control" value="Funky Chicken" placeholder="Name is..." id="myText">
<div class="d-flex justify-content-end">
<span id="wordCount" class="text-muted">0</span>
<span class="text-muted">/</span>
<span class="text-muted">256</span>
</div>
You can achieve this by setting the initial value of the wordCount element to the length of the value attribute of the myText input element, rather than 0. This can be done by adding this line of code before the event listener:
var myText = document.getElementById("myText");
var wordCount = document.getElementById("wordCount");
wordCount.innerText = myText.value.length;
myText.addEventListener("keyup",function(){
var characters = myText.value.split('');
wordCount.innerText = characters.filter( item => {
return (item != ' ');
}).length;
});
<input type="text" name="name" class="form-control" value="{{ $employee->name }}" placeholder="Name is..." id="myText">
<div class="d-flex justify-content-end">
<span id="wordCount" class="text-muted">0</span>
<span class="text-muted">/</span>
<span class="text-muted">256</span>
</div>

How can I get my JS code to store multiple entries from a form through adding/removing fields?

(function($) {
"use strict";
var itemTemplate = $('.input_fields_wrap'),
editArea = $('.edit-area'),
itemNumber = 1;
$(document).on('click', '.edit-area .add', function(event) {
event.preventDefault();
var item = itemTemplate.clone();
$(item).find("input[type=text]", "input[type=textarea]", "input[type=number]").removeAttr(0).val('');
item.find('[partNum]').attr('partNum', function() {
return $(this).attr('partNum') + '_' + itemNumber;
});
++itemNumber;
item.appendTo(editArea);
});
$(document).on('click', '.edit-area .rem', function(event) {
event.preventDefault();
var total_fields = itemTemplate[0].childNodes.length;
if (total_fields > 1) {
editArea.children('.input_fields_wrap').last().remove();
}
});
$(document).on('click', '.edit-area .del', function(event) {
var target = $(event.target),
row = target.closest('.input_fields_wrap');
row.remove();
});
}(jQuery));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="product_titles">
<h5 class="titles">Item/Part Number</h5>
<h5 class="titles">Product Description</h5>
<h5 class="titles">Quantity</h5>
<div class="edit-area">
<button type="button" class="rem">-</button>
<button type="button" class="add">+</button>
<br><br>
</div>
</div>
<div class="input_fields_wrap">
<label for="contactFormPartNumber" class="hidden-label">{{ 'contact.form.part_number' | t }}</label>
<div class="formfield"><input type="text" id="contactFormPartNumber" name="contact[{{ 'contact.form.part_number' | t }}]" placeholder="{{ 'contact.form.part_number' | t }} *" required="required"></div>
<div class="formfield"><input type="text" name="description" placeholder="Product Description"></div>
<div class="formfield"><input type="number" id="contactQuantity" name="contact[{{ 'contact.form.quantity' | t }}]" value="0" min="0" required="required"></div>
</div>
Okay so the problem I have been facing is that every time a new field is created it lets the user type the data but doesn't store it anywhere. I think using arrays might work but I'm not quite sure how I'm supposed to integrate that in my code. Also a weird thing that happens when I create a new field using the buttons is it pushes my first field down but after that the next fields after the second one somehow sandwich between field 1 and 2. I don't quite know why that happens. Any help is appreciated!

A question about usage of cloneNode and insertBefore

I am trying to learn some javascript in web programming. Starting with a simple school registration webpage: the webpage allows to dynamically create any number of grades by clicking "Grade+" button; under each grade, any number of students can be created by clicking "Student+" button. "Grade+" button works as expected, however clicking "Student+" button does not present the student information, not sure what is happening. Any help will be highly appreciated. Thanks in advance.
The reference codes:
<!DOCTYPE html>
<html>
<body>
<div>
<label>Registration</label>
<div class="form-inline justify-content-center" id="school" style="display:none">
<label for="fname">Grade:</label>
<input type="text" id="grade" name="Grade"><br><br>
<div id="students">
<div id="student">
<label for="fname">First:</label>
<input type="text" id="first" name="First"><br><br>
<label for="lname">Last:</label>
<input type="text" id="last" name="Last"><br><br>
</div>
<div class="text-center" id="add_student">
<span id="idStudentRootCopy">----S----</span>
<button type="button" onclick="addItem('student', 'idGradeRootCopy', false)">Student+</button>
</div>
</div>
</div>
<div class="text-center" id="add_grade">
<span id="idGradeRootCopy">----G----</span>
<button type="button" onclick="addItem('school', 'idGradeRootCopy', true)">Grade+</button>
</div>
</div>
<script>
var count = 0;
function addItem(id, index, root) {
var original = document.getElementById(id);
var before = document.getElementById(index);
var clone = original.cloneNode(true);
clone.style.display='block';
clone.id = id + ++count;
var newFields = clone.childNodes;
for (var i = 0; i < newFields.length; i++) {
var fieldName = newFields[i].name;
if (fieldName)
newFields[i].name = fieldName + count;
}
if (root) {
original.parentNode.insertBefore(clone, before.parentNode);
} else {
original.insertBefore(clone, before);
}
}
</script>
</body>
</html>
If you open up the developer tools of your browsers and click the Student+ button you'll get an error message like:
Uncaught DOMException: Node.insertBefore: Child to insert before is
not a child of this node
So you're actually trying to put the cloned node into the wrong spot. Either way things are a bit confusing. Let's say you have clicked the Grade+ button three times and now you decide to click on Student+ of the first clone - how should it know where to put the student as there are three grades?
Well there's a fix of course. Each Student+ button is a child of an unique clone of the school <div> which you also gave an unique id yet (school1, school2,...). So if you pass the addItem() function a reference to the button you actually clicked, we can get it's parent div like:
clickedElement.parentNode.parentNode.parentNode
and add the cloned node using appendChild() instead of insertBefore().
Here's an example (just click on 'Run code snippet'):
var count = 0;
function addItem(id, index, root, clickedElement) {
var original = document.getElementById(id);
var before = document.getElementById(index);
var clone = original.cloneNode(true);
clone.style.display = 'block';
clone.id = id + ++count;
var newFields = clone.childNodes;
for (var i = 0; i < newFields.length; i++) {
var fieldName = newFields[i].name;
if (fieldName)
newFields[i].name = fieldName + count;
}
if (root) {
original.parentNode.insertBefore(clone, before.parentNode);
} else {
clickedElement.parentNode.parentNode.parentNode.appendChild(clone);
}
}
<div>
<label>Registration</label>
<div class="form-inline justify-content-center" id="school" style="display:none">
<label for="fname">Grade:</label>
<input type="text" id="grade" name="Grade"><br><br>
<div id="students">
<div id="student">
<label for="fname">First:</label>
<input type="text" id="first" name="First"><br><br>
<label for="lname">Last:</label>
<input type="text" id="last" name="Last"><br><br>
</div>
<div class="text-center" id="add_student">
<span id="idStudentRootCopy">----S----</span>
<button type="button" onclick="addItem('student', 'idGradeRootCopy', false,this)">Student+</button>
</div>
</div>
</div>
<div class="text-center" id="add_grade">
<span id="idGradeRootCopy">----G----</span>
<button type="button" onclick="addItem('school', 'idGradeRootCopy', true,this)">Grade+</button>
</div>
</div>
Update
If you click on the Grade+ button, it will automatically also 'create' a student input field as it's div is part of the school div. So move it out of the school div and change it's display mode to none.
If you want the new student input field to appear right before the Student+ button, we indeed need to use .insertBefore().
Here's the modified example:
var count = 0;
function addItem(id, index, root, clickedElement) {
var original = document.getElementById(id);
var before = document.getElementById(index);
var clone = original.cloneNode(true);
clone.style.display = 'block';
clone.id = id + ++count;
var newFields = clone.childNodes;
for (var i = 0; i < newFields.length; i++) {
var fieldName = newFields[i].name;
if (fieldName)
newFields[i].name = fieldName + count;
}
if (root) {
original.parentNode.insertBefore(clone, before.parentNode);
} else {
clickedElement.parentNode.insertBefore(clone, clickedElement);
}
}
<div>
<label>Registration</label>
<div id="student" style="display:none">
<label for="fname">First:</label>
<input type="text" id="first" name="First"><br><br>
<label for="lname">Last:</label>
<input type="text" id="last" name="Last"><br><br>
</div>
<div class="form-inline justify-content-center" id="school" style="display:none">
<label for="fname">Grade:</label>
<input type="text" id="grade" name="Grade"><br><br>
<div id="students">
<div class="text-center" id="add_student">
<span id="idStudentRootCopy">----S----</span>
<button type="button" onclick="addItem('student', 'idStudentRootCopy', false,this)">Student+</button>
</div>
</div>
</div>
<div class="text-center" id="add_grade">
<span id="idGradeRootCopy">----G----</span>
<button type="button" onclick="addItem('school', 'idGradeRootCopy', true,this)">Grade+</button>
</div>
</div>

cash denomination calculator

I've created cash denomination calculator in jquery, and it's working fine once you add entry but suppose if you try to change those entries then it's not calculating values as i expected.
Just fill those values and you'll get total of all, but if try to change the value of input box inside div with '.mul_by' class[i.e. the small input box before '=' sign] then it's not calculating the total properly.
And here's the jsFiddle for the same.
$('.mul_by').each(function (i) {
var _this = $(this),
//set default input value to zero inside .mul-by div
setZero = _this.find('.form-control').val(0),
//set default input value to zero inside .mul-val div
setDenominationVal = _this.siblings('.mul_val').find('.form-control').val(0),
//set default input value to zero inside .total div
setTotalVal = $('.total').val(0);
setZero.on('change', function () {
//watch and store input val. inside .mul_by
var getUpdatedVal = _this.find('.form-control').val(),
//get label text
getDenominationVal = parseInt(_this.siblings('label').text()),
//update mul_by div after multiplication
updateDenominationVal = _this.siblings('.mul_val').find('.form-control');
if (getUpdatedVal > 0) {
var vals = updateDenominationVal.val(getUpdatedVal * getDenominationVal);
total = parseInt(setTotalVal.val()) + parseInt(vals.val());
setTotalVal.val(total);
} else {
updateDenominationVal.val(0);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form class="form-horizontal">
<div class="form-group">
<label class="control-label col-md-2 col-xs-2" for="batch">2000</label>
<div class="col-md-1 col-xs-4 mul_by">
<span>x </span> <input type="text" class="form-control">
</div>
<div class="col-md-3 col-xs-5 mul_val">
<span style="font-size: 18px;">= </span> <input type="text" class="form-control">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2 col-xs-2" for="batch">500</label>
<div class="col-md-1 col-xs-4 mul_by">
<span>x </span> <input type="text" class="form-control">
</div>
<div class="col-md-3 col-xs-5 mul_val">
<span style="font-size: 18px;">= </span> <input type="text" class="form-control">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2 col-xs-2" for="batch">100</label>
<div class="col-md-1 col-xs-4 mul_by">
<span>x </span> <input type="text" class="form-control">
</div>
<div class="col-md-3 col-xs-5 mul_val">
<span style="font-size: 18px;">= </span> <input type="text" class="form-control">
</div>
</div>
<div class="form-group">
<hr>
<label class="control-label col-md-2 col-xs-2" for="batch">total:</label>
<div class="col-md-3 col-xs-5 mul_val">
<span style="font-size: 18px;">= </span> <input type="text" class="form-control total">
</div>
</div>
</form>
How do i update total after making changes?
Hope you understand it. Thanks in advance for your help.
Please check this code i get proper result I had made lot of changes at end hope you will get desired result:-
$(document).ready(function () {
$('.mul_by').each(function (i) {
var _this = $(this),
//set default input value to zero inside .mul-by div
setZero = _this.find('.form-control').val(0),
//set default input value to zero inside .mul-val div
setDenominationVal = _this.siblings('.mul_val').find('.form-control').val(0);
//set default input value to zero inside .total div
setTotalVal = $('.total').val(0);
setZero.on('change', function () {
var getcurrentval = $(this).val();
console.log('getcurrentval',getcurrentval)
//watch and store input val. inside .mul_by
var getUpdatedVal = _this.find('.form-control').val(),
//get label text
getDenominationVal = parseInt(_this.siblings('label').text()),
//update mul_by div after multiplication
updateDenominationVal = _this.siblings('.mul_val').find('.form-control');
console.log(getUpdatedVal,getDenominationVal)
var vals = 0,total=0;
if(getUpdatedVal > 0){
if(updateDenominationVal.val()>0){
vals = updateDenominationVal.val(getUpdatedVal * getDenominationVal - updateDenominationVal.val());
total = parseInt(setTotalVal.val()) + parseInt(vals.val()) ;
updateDenominationVal.val(getUpdatedVal * getDenominationVal);
console.log('total',total,'setTotal',setTotalVal.val(),vals.val());
}
else{
vals = updateDenominationVal.val(getUpdatedVal * getDenominationVal);
updateDenominationVal.val(getUpdatedVal * getDenominationVal);
total = parseInt(setTotalVal.val()) + parseInt(vals.val());
}
console.log(vals.val());
setTotalVal.val(total);
} else{
updateDenominationVal.val(0);
}
});
});
});

How do I get a <div> on a nearby node in the DOM?

I'm trying to write some JavaScript that could be used throughout my app, and allow a checkbox to show/hide a nearby element.
If I have these elements:
<div class="optionable" style="display: block;">
<div class="row">
<div class="col-md-2">
<input checked="checked" class="form-control"
data-val="true" id="IsActive"
name="IsActive"
onclick="CheckboxOptionsToggle(this);"
type="checkbox" value="true">
</div>
<div class="col-md-8">
Chapter
</div>
</div>
<div class="row options">
<div class="col-md-12">
Some data here...
</div>
</div>
</div>
And this script:
CheckboxOptionsToggle = function (thisCheckbox) {
debugger;
var optionElement = $('.options');
if (thisCheckbox.checked) {
$(thisCheckbox).closest(optionElement).show();
} else {
$(thisCheckbox).closest(optionElement).hide();
}
}
But this isn't working. I would like the checkbox with the onclick="CheckboxOptionsToggle(this);" to trigger the options element in the same optionable div to either show or hide.
What am I doing wrong in my JavaScript/jQuery?
UPDATE: This is my final solution:
$('.optionToggle').on('change', function () {
$(this).closest('.optionable').find('.options').toggle(this.checked);
});
$(document).ready(function () {
var toggleElements = document.body.getElementsByClassName('optionToggle');
for (var i = 0; i < toggleElements.length; i++) {
var thisCheck = $(toggleElements[i]);
thisCheck.closest('.optionable').find('.options').toggle(thisCheck.prop('checked'));
}
});
<div class="optionable" style="display: block;">
<div class="row">
<div class="col-md-2">
<input checked="checked" class="form-control optionToggle"
data-val="true" id="IsActive"
name="IsActive"
type="checkbox" value="true">
</div>
<div class="col-md-8">
Chapter
</div>
</div>
<div class="row options">
<div class="col-md-12">
Some data here...
</div>
</div>
</div>
Be more generic, and stop using inline event handlers
$('[type="checkbox"]').on('change', function() { // or use class to not attach to all
$(this).closest('.optionable').find('.options').toggle(this.checked);
}).trigger('change');
FIDDLE
You can change it like
CheckboxOptionsToggle = function (thisCheckbox) {
debugger;
var optionElement = $('.options');
if (thisCheckbox.checked) {
$(thisCheckbox)..closest('div.optionable').find(optionElement).show();
} else {
$(thisCheckbox)..closest('div.optionable').find(optionElement).hide();
}
}
I would stay away from .closes, because it is so specific, instead I would go with more reusable code like so:
HTML:
<input type="checkbox" id="toggler" data-target-class="some-div" class="toggler" value="myValue" checked> Toggle Me
<div class="some-div">
Some Text within the div.
</div>
JS:
$('#toggler').on('click', function() {
var targetClass = $(this).data('target-class');
$('.' + targetClass).toggle($(this).checked);
});
JSFiddler: https://jsfiddle.net/ro17nvbL/
I am using data element on the checkbox to specifiy which divs to show or hide. This allows me to not only hide/show divs but anything n the page, and not only one instance but as many as needed. Way more flexible - still does the same job.

Categories

Resources