jQuery find() & each() on dynamic elements - javascript

I've got a <div> element that contains multiple other <div>'s that are populated dynamically using jQuery/Ajax, I'm trying to run the following code but find() fails to get any of them.
Here's my HTML boilerplate prior to my data being populated.
<input type="text" id="inv-filter" class="form-control">
<div class="row itemList" style="margin-right: -2px;margin-left:-2px;">
</div>
And here's what it looks like after population.
<input type="text" id="inv-filter" class="form-control">
<div class="row itemList" style="margin-right: -2px;margin-left:-2px;">
<div class="col-xs-3 col-sm-2 shop-item" data-hash="Item Name 1">
</div>
<div class="col-xs-3 col-sm-2 shop-item" data-hash="Item Name 2">
</div>
......
</div>
My Javascript looks like the following:
$('#inv-filter').keyup(function() {
var search = $(this).val().toLowerCase();
var $sellContainer = $('.itemList');
if (search.trim() === '') {
$sellContainer.find('.shop-item').show();
$sellContainer.find('.shop-item.selected').hide();
return;
}
$sellContainer.find('.sell-item').each(function() {
if (!$(this).hasClass('selected') && $(this).data('hash').text().toLowerCase().includes(search)) {
$(this).show();
} else {
$(this).hide();
}
});
});
I've ran multiple tests inside console debugger such as $('.itemList').length() etc.. but doesn't appear to find any results & when entering text into my input field, nothing is happening

$sellContainer.find('.sell-item').each(function() { //replace sell-item with shop-item
if (!$(this).hasClass('selected') && $(this).data('hash').text().toLowerCase().includes(search)) {
$(this).show();
} else {
$(this).hide();
}
});

Related

Loop through all inner elements of HTML and check if field is required

I'm working on a complex multipage form using HTML, Bootstrap and JavaScript.
What I'm trying to figure out is to validate each section of the multipage form and check if all required fields (if any) are actually valid so that the user can proceed to next section in the form.
The following code snippet is a simplification of my modified form:
<div class="card">
<form id="myform">
<div class="card-body">
<div class="section-1">
<div class="field-1">
<fieldset>...</fieldset>
<input required id="input-field-1">
</div>
<div class="field-2">
<fieldset>...</fieldset>
<select required id="input-field-2">
</div>
<div class="field-3">
<fieldset>...</fieldset>
<div class="nested NODE">
<input required id="input-field-3">
</div>
</div>
<div class="field-4">
<fieldset>...</fieldset>
<div class="nested NODE">
<div class="really nested NODE">
<div class="very big nested NODE">
<input required id="input-field-4">
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
What is the most efficient way of getting all required fields? For now I'm iterating through each item in the section-1 and get the inner parts to check validity. But using my code below, it will not work on complex nested nodes. How to prevent that?
function find("required", section_number) {
let elements = document.getElementById("form_section_" + section_number);
let children = document.getElementById("form_section_" + section_number).children;
console.log(children);
for(var i=0; i<children.length; i++){
console.log(children[i].childNodes.length);
if(children[i].childNodes.length == 0){
if (children[i].childNodes.required) {
console.log('✅ element is required');
} else {
console.log('⛔️ element is not required');
}
}
else{
for(var y=0; y<children[i].childNodes.length; y++){
console.log("inner loop = " + i + ":" + y);
if (children[i].childNodes[y].required) {
console.log('✅ element is required');
} else {
console.log('⛔️ element is not required');
}
}
}
}
return false;
}
If you just want to check if your form is valid, use checkValidity(). If you want some custom handling, you could try selecting all the possible fields and then loop over them to validate the field individually.
For instance: (this list is not complete)
document.querySelectorAll('input, select, textarea');

Dynamic slideToggle function with given html class id parameters

I have a question about to creating dynamic jquery slideToggle function. I have html template as below:
<h4 id="client" class="section-title">
<div class="sect-icon"></div>
<span>Client Info</span> </h4>
<div class="form-row" id="client_data">
<div class="form-group col-md-4">
<label for="id_client_name">Name</label>
<input class="form-control" disabled value="{{client.client_name}}">
</div>
</div>
And jQuery function as :
$(document).ready(function () {
$("#client").click(function () {
if ($('#client_data').is(':visible')) {
$("#client").removeClass("section-title");
$("#client").addClass("section-title closed");
} else {
$("#client").removeClass("section-title closed");
$("#client").addClass("section-title");
}
$("#client_data").slideToggle("fast");
});
It is work . But this jQuery function is only for concreate html class. If i append another class to html ,then i should be copy this jQuery and past and edit id part. But i want to write one jQuery function for dynamic html id.
I mean how i can use above jQuery function for below html without creating new jQuery
<h4 id="equip" class="section-title">
<div class="sect-icon"></div> <span>Calibrated Equipment</span></h4>
<div class="form-row" id="equip_data">
<div class="form-group col-md-4">
<label for="id_brand_name">Brand</label>
<input class="form-control" disabled value="{{equip.brand_name}}">
</div>
</div>
When I was a university student, a teacher told us that repeated code is called "function":
function myStuff(idText) {
$("#" + idText).click(function () {
if ($('#' + idText + "_data").is(':visible')) {
$("#" + idText).removeClass("section-title").addClass("section-title closed");
} else {
$("#" + idText).removeClass("section-title closed").addClass("section-title");
}
$("#" + idText).slideToggle("fast");
}
And you pass the id to myStuff whenever you want, like:
$(document).ready(function () {
myStuff("client");
});

Removing selected row from an array using splice in angularjs

I have an issue in removing the particular item from an array.I have tried using splice but, the last row is removing instead of the particular row.I am providing the plunker link here :
$scope.rows.splice($index, 1);
https://plnkr.co/edit/WETSLqOXlTwiHq4p9IUt?p=preview
Any help would be appreciated . Thanks
just try the following
http://jsfiddle.net/oymo9g2f/2/
you have some problem with your array splice
Not quite sure what you're trying to accomplish (as your code looks like you are quite new to AngularJS, but I created a different (but similar) implementation that should fit your needs (it's easier to read IMHO and is scalable):
HTML:
<div class="card ">
<form name="add_destination_form" class="col s12" ng-submit="add_destination_form.$valid && addDestination_Details(destination_details)" novalidate>
<div class="row" ng-repeat="row in rows track by $index">
<div class="col s12 m4" >
<label for="destination_features1" >Features</label>
<textarea id="destination_features1" name="destination_features1_{{$index}}" ng-model="destination_details.destination_features1[$index]" placeholder="Data Here" type="text" ></textarea>
</div>
<button ng-show="show_removebtn" id="removeButton" ng-click="removeDynamically($index)" type="button">Remove</button>
</div>
<div class="col s12 m4">
<button class="waves-effect waves-light btn" ng-click="addDynamically()" type="button">Add More</button>
</div>
<div class="row">
<div class="col s12 m4">
<button type="submit">Submit</button>
</div>
</div>
</form>
</div>
JavaScript:
$scope.rows = [{
"row_num": 0,
"text": ""
}];
$scope.addDynamically = function (index) {
console.log(index);
$scope.rows.push({
"row_num": index,
"text": ""
});
};
$scope.removeDynamically = function (index) {
$scope.rows.splice(index, 1);
};
Plunker
just use this code. For text area used ng-model="row.value" and related change in controller
in html: just shown ng-repeat part
<div class="row" ng-repeat="row in rows track by $index">
<div class="col s12 m4" >
<label for="destination_features1" >Features</label>
<textarea id="destination_features1" name="destination_features1_{{$index}}" ng-model="row.value" placeholder="Data Here" type="text" ></textarea>
</div>
<button ng-show="show_removebtn" id="removeButton" ng-click="removeDynamically($index)" type="button">Remove</button>
</div>
and in controller:
$scope.rows = [];
$scope.current_rows = 0;
$scope.destination_details = {};
$scope.rows.push({
row_num: $scope.current_rows,
value: ''
});
$scope.addDynamically = function() {
$scope.current_rows += 1;
$scope.rows.push({
row_num: $scope.current_rows,
value: ''
});
if ($scope.rows.length > 1) {
$scope.show_removebtn = true;
}
};
$scope.removeDynamically = function(index) {
if (index > -1) {
$scope.rows.splice(index, 1);
}
};
You need to add line:
$scope.destination_details = {"destination_features1": ['1']};
at the beginning.
Also need to remove model properly when removing element:
$scope.destination_details.destination_features1.splice($index, 1);
https://plnkr.co/edit/pe44Moqe7ymegYFTrXJu?p=preview

Why isn't meteor injecting the text from my template helpers?

Im trying to dynamically generate a table of two different sets of data. My database isnt empty and the returns have been verified as well. but when i check the rendered page the corresponding html isnt there as if nothing as returned.
template/html:
<template name="room">
<div class="container-fluid">
<h1> Sprint Retrospective</h1>
<hr>
<div class="input-group">
<input type="text" class="form-control thoughts" placeholder="Thoughts..." aria-describedby="basic-addon1">
<span class="input-group-addon">
<input id="wentWell" type="checkbox" aria-label="..."> Went Well
</span>
<span class="input-group-addon">
<input id="wentWrong" type="checkbox" aria-label="..."> Went Wrong
</span>
<span class="input-group-btn">
<button class="btn btn-default" type="button">Submit!</button>
</span>
</div>
<hr>
{{#if haveCards}}
<div class="container-fluid">
<div class="row">
<div class="col-xs-6 col-sm-6">
<div class="row">Went Well</div>
{{#each wentWell}}
{{>card}}
{{/each}}
</div>
<div class="col-xs-6 col-sm-6">
<div class="row">Went Wrong</div>
{{#each wentWrong}}
{{>card}}
{{/each}}
</div>
</div>
</div>
{{/if}}
</div>
</template>
Javascript:
"use strict";
/**
*
**/
var Cards = new Mongo.Collection('cards');
var allCards;
var wentWellCards;
var wentWrongCards;
if(Meteor.isClient){
Tracker.autorun(function(){
allCards = Cards.find({},{sort:{createdAt:-1}});
wentWellCards = Cards.find({category:"Went Well"},{sort:{createdAt:-1}});
wentWrongCards = Cards.find({category:"Went Wrong"},{sort:{createdAt:-1}});
});
Template.room.helpers({
haveCards: function(){
if(allCards != null && allCards != undefined && allCards.length > 0)
return true;
return false;
},
wentWell: function(){
return this.wentWellCards;
},
wentWrong: function(){
return this.wentWrongCards;
}
});
}
Jeremy answer its actually more in point, but..
Lets try to fix that code a little bit.
Lets change the wentWell and wentWrong helpers to look more clean like this.
wentWell: function(){
return Cards.find({category:"Went Well"},{sort:{createdAt:-1}});
},
wentWrong: function(){
return Cards.find({category:"Went Wrong"},{sort:{createdAt:-1}});
}
Also for the haveCards helpers you can do something like
haveCards: function(){
return Cards.find().count() >= 1 //for example or return just findOne()
}
Your helpers should return wentWellCards instead of this.wentWellCards, etc.
Your helpers are not reactive, so, when the data is loaded (which happens after the page is rendered) the helpers are not re-run.
Simply, call the reactive methods (the minimongo queries) in the helper directly. This will get them re-run once the data is available
Also, when you check the count, you need to fetch the collection
Cards = new Mongo.Collection('cards');
if(Meteor.isServer){
Meteor.publish('cards', function() {
return Cards.find({},{sort:{createdAt:-1}});
});
}
if(Meteor.isClient){
Template.room.onCreated(function(){
this.subscribe('cards');
});
Template.room.helpers({
haveCards: function(){
var allCards = Cards.find({},{sort:{createdAt:-1}}).fetch();
return (allCards != null && allCards != undefined && allCards.length > 0);
},
wentWell: function(){
return wentWellCards = Cards.find({category:"Went Well"},{sort:{createdAt:-1}});
},
wentWrong: function(){
return wentWrongCards = Cards.find({category:"Went Wrong"},{sort:{createdAt:-1}});
}
});
}
And you will need to publish the collection from the server and subscribe from the template (unless you are using autopublish)

Jquery stop repeat my code with after?

I have a problem with my input and my Jquery :
Basically I have this code :
HTML:
<form id="formUser">
<div class="row">
<div class="small-8">
<div class="row">
<div class="small-6 columns">
<label for="right-label" class="right inline">First name</label>
</div>
<div class="small-6 columns">
<input type="text" name="fisrtName" placeholder="First name">
</div>
</div>
</div>
</div>
<div class="row text-center">
<input type="checkbox" class="check"><label for="checkbox"><p>I accept the review agreement</p></label>
<button type="submit" class="button join">Let's Go !</button>
</div>
</form>
JS :
<script type="text/javascript">
$(function(){
$("#formUser").submit(function(){
if(!$('input[name="fisrtName"]').val()) {
$('input[name="fisrtName"]').addClass("error");
$('input[name="fisrtName"]').after("<small class='error'>Invalid entry</small>");
}
return false;
});
});
</script>
And I have this
When I click several time on the button... the error class is repeat ..
How can i stop the repeat or incrase the actual class error ?
Maybe you should be doing something like this
$("#formUser").submit(function(){
var $element = $('internal[name="fisrtName]');
// ^ save this much faster ^
// ^ you have spelt firstName wrong also ^
// check val and check next element isn't error
if($element.val() && $element.next().hasClass('error') === false) {
$element.addClass('error').after("<small class='error'>Invalid entry</small>");
} else {
// now remove it if you need to
}
return false;
});
Hope it helps.
You should always cache your elements
By doing this:
$('internal[name="fisrtName');
$('internal[name="fisrtName');
$('internal[name="fisrtName');
You're calling the jQuery function 3 times when you do not need to.
You can use:
if($('input[name="fisrtName"]').find('.error').length==0)
$('input[name="fisrtName"]').after("<small class='error'>Invalid entry</small>");
Or:
var $firstName = $('input[name="fisrtName"]');
if (!$firstName.hasClass("error")) {
$firstName.addClass("error");
$firstName.after("<small class='error'/>");
}
$firstName.find("small.error").text("Invalid entry");
Try to change your code with this, I have aded the line "$('small.error').remove();"
$.q("#formUser").submit(function(){
if(!$.q('input[name="fisrtName"]').val()) {
$.q('small.error').remove();
$.q('input[name="fisrtName"]').addClass("error");
$.q('input[name="fisrtName"]').after("<small class='error'>Invalid entry</small>");
}
return false;
});

Categories

Resources