I am trying to convert a small script from javascript to jquery, but I don't know where I should be putting the [i] in jquery?. I am nearly there, I just need someone to point out where I have gone wrong.
This script expands a search input when focused, if the input contains any values, it retains it's expanded state, or else if the entry is removed and clicks elsewhere, it will snap back.
Here is the javascript:
const searchInput = document.querySelectorAll('.search');
for (i = 0; i < searchInput.length; ++i) {
searchInput[i].addEventListener("change", function() {
if(this.value == '') {
this.classList.remove('not-empty')
} else {
this.classList.add('not-empty')
}
});
}
and converting to jquery:
var $searchInput = $(".search");
for (i = 0; i < $searchInput.length; ++i) {
$searchInput.on("change", function () {
if ($(this).value == "") {
$(this).removeClass("not-empty");
} else {
$(this).addClass("not-empty");
}
});
}
Note the key benefit of jQuery that it works on collections of elements: methods such as .on automatically loop over the collection, so you don't need any more than this:
$('.search').on("change", function() {
this.classList.toggle('not-empty', this.value != "");
});
This adds a change event listener for each of the .search elements. I've used classList.toggle as it accepts a second argument telling it whether to add or remove the class, so the if statement isn't needed either.
Related
I am developing an app that allows user to search for fishing lakes in their area. To do this they can type in their location which then displays fisheries near them that i have identified in the Json data. The search works perfectly with the code below i have written (i know it maybe a little flaky as i am not the best programmer).
//search
$(document).ready(function(){
$('#exampleSearch').keyup(function() {
var searchVal = $('#exampleSearch').val();
$('#results').empty();
console.log(searchVal);
var results = [];
$.getJSON("/data/locations.json",function(locations) {
for (var i = 0; i < locations.length; i++) {
if (locations[i].location.match(searchVal)) {
results.push(locations[i]);
}
}
$.each(results, function(index,result) {
var $resultsLi = $(
'<div class="row">'+
'<div class="twelve columns profile-information ">'+
'<div class="profile-title">'+
'<h6>'+result.name+'</h6>'+
'</div> ' +
' <img class= "favourites-pic" src="'+ result.image +'" alt="Fishery">'+
'<a class="view" href="'+ result.url + '" >View</a>'+
'</div>'+
' </div>'
)
$("#results").append($resultsLi);
});
});
});
});
I have now added a feature where users can now add their search results to their favourites page, by click a Add to favorites button on the page of the fishery they found from their search with the following code:
Javascript:
//Add to Favourites
$(function() {
$( ".addFavourites" ).on("click", function() {
try {
$(this).attr('disabled', true);
var locIdToAdd = $(this).closest("p").attr("id");
var myFavouriteLoc=JSON.parse(localStorage.getItem("favLoc"));
if (myFavouriteLoc == null) {
myFavouriteLoc = [];
}
if (myFavouriteLoc != null) {
for ( var j = 0; j < myFavouriteLoc.length; j++) {
if ( locIdToAdd == myFavouriteLoc[j]) {
alert("This property is already in your favourites");
myFavouriteLoc = [];
}
}
}
myFavouriteLoc.push(locIdToAdd);
localStorage.setItem("favLoc", JSON.stringify(myFavouriteLoc));
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
console.log("Error: Local storage limit exceeds");
} else {
console.log("ERROR: Saving to local storge.");
}
}
});
});
Html:
<p id="loc 1">
<input class="button-primary green addFavourites" type="submit" value="Add to Favourites">
</p>
THE PROBLEM
Upon clicking the 'view' button on the search page results, and navigating to a fishery page. I have a problem where i have to then refresh the page again before the add to favourites button will add anything to the local storage, it is clickable, but nothing happens. once i refresh the page it works fine.
Can anyone help with why i have to refresh the page first? any help is a appreciated :)
Try this jquery code to add favorites, it should work on each click:
$( document ).on("click", ".addFavourites", function(e) {
e.preventDefault();
try {
$(this).attr('disabled', true);
var locIdToAdd = $(this).closest("p").attr("id");
var myFavouriteLoc=JSON.parse(localStorage.getItem("favLoc"));
if (myFavouriteLoc == null) {
myFavouriteLoc = [];
}
if (myFavouriteLoc != null) {
for ( var j = 0; j < myFavouriteLoc.length; j++) {
if ( locIdToAdd == myFavouriteLoc[j]) {
alert("This property is already in your favourites");
myFavouriteLoc = [];
}
}
}
myFavouriteLoc.push(locIdToAdd);
localStorage.setItem("favLoc", JSON.stringify(myFavouriteLoc));
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
console.log("Error: Local storage limit exceeds");
} else {
console.log("ERROR: Saving to local storge.");
}
}
});
Just make sure you are not putting this jquery function inside $(document).ready(function(){}) or $(function(){}) because it is not required
I can't see any code relating to loading the list of favourites, but I think it's fair to assume to that when the page loads you're loading the items from storage and placing them in, and then the pages where you add favourites and view favourites don't involve any loading between them. Therefore, of course, loading the items for the favourites list will only be performed on load, and so placing new items into the localStorage without reloading will not add them. So I'm going to cover a few things.
Firstly, don't use == and !=. They perform type coercion, (numbers to strings, strings to numbers, null to undefined, etc.), the rules for which are unintuitive and unmemorable and are best simply avoided, lest they cause difficult to diagnose problems in your code. Use === and !== instead, these behave just like == and != does in other languages. If you want to perform type coercion I'd do so explicitly (e.g. Number('5')).
Secondly, and just as a suggestion, if you implement the local storage as an object, you won't need to loop and can simply use property names. So you can replace
if (myFavouriteLoc != null) {
for ( var j = 0; j < myFavouriteLoc.length; j++) {
if ( locIdToAdd == myFavouriteLoc[j]) {
With simply
if (myFavouriteLoc && myFavouriteLoc[locIdToAdd]) {
// ...
}
The object && object.property idiom will perform a truthy check on both the object and the property, only passing if they are both truthy (not falsy). Here's a list of falsy values.
So, to answer your actual question. I'd say you have two options:
Reload the page on each addition, or
AJAXily add the entry to your views when favourites are added. Favourites will then, of course, need be removed
Going with my assumption in the first paragraph, I'd say that the second option is your best bet, as the constant page refreshes would provide a bad user experience.
So here's the jsfiddle
(function bindBtns() {
$('.Table-btn--add').click(function () {
addBinding($(this));
});
$('.Table-btn--remove').click(function () {
removeBinding($(this));
});
})();
Here is an immediately invoked function, meaning it's run straight away. This will bind the existing buttons' behaviour, depending on whether they are add or remove buttons.
function addBinding($btn) {
$btn.parent()
.detach()
.appendTo($('#favourites'));
// add to local storage here
modifyAttributes($btn);
}
Here's the behaviour for the binding, fairly straight forward, but:
Select the buttons parent, i.e. the row
Detach it from the DOM, i.e. the current table
Attach it to the other table
Rebind the button to perform the opposite behaviour, shown below
Place your behaviour for adding or removing from local storage where I've placed the comments.
removeBinding is exactly the same except it appends to the other table.
function modifyAttributes($btn) {
if ($btn.hasClass('Table-btn--add')) {
$btn.text('Remove')
.removeClass('Table-btn--add')
.addClass('Table-btn--remove')
.off('click')
.click(removeBinding.bind(null, $btn));
} else if ($btn.hasClass('Table-btn--remove')) {
$btn.text('Add')
.removeClass('Table-btn--remove')
.addClass('Table-btn--add')
.off('click')
.click(addBinding.bind(null, $btn));
}
}
Split on whether this is an adding button, or a removing button. (The next steps will be for both versions.)
Update the text to be the opposite, (add -> remove, remove -> add)
Remove the current class
Add the new class
Remove the old click binding
Bind the new click binding. Read about .bind here
In your version you would replace .Table-btn--add with .addFavourites, and place addBinding($(this)) in your try block, and then you can just copy over the other functiona verbatim (I think).
Good luck! Sorry that got so long, and let me know how it goes.
I have a webform with a control panel (#pnlStepOne). The panel includes two textfields "txtFname" and "txtLname". I have a validator setup for each textfield. I have tested the form and all works as desired.
My questions is how do I add a jQuery effect to the panel onclick event only if one (or both) of the textfields ("txtFname" and "txtLname") don't validate. (this effect would "shake" the panel).
And I would like to add another jQuery effect to "flip" the control panel and switch the current one (#pnlStepOne) for another one (#pnlStepTwo) if both fields are validated by the asp:RequiredFieldValidators.
Just a sample code that I will tweak once I have the right If condition.
$(document).ready(function () {
$("#btnStepOne").click(function (event) {
if (**this is the condition that I am missing**)
{
$('#pnlStepOne').css({
background: 'red',
});
}
});
});
You can modify your code to be like this:
$(document).ready(function () {
$("#btnStepOne").click(function (event) {
var fvFname = document.getElementById('client-id-of-your-fvFname-validator');
var fvLname = document.getElementById('client-id-of-your-fvLname-validator');
ValidatorValidate(fvFname);
ValidatorValidate(fvLname);
if (!fvFname.isvalid || !fvLname.isvalid) {
$('#pnlStepOne').css({
background: 'red',
});
}
});
});
Have a rad of my answer to a similar question here:
Enable/Disable asp:validators using jquery
Which has the MSDN link here: http://msdn.microsoft.com/en-us/library/aa479045.aspx
In one of my projects I use a prettifyValidation function, so you could have something like:
$(document).ready(function () {
$("#btnStepOne").click(function (event) {
prettifyValidation();
});
});
function prettifyValidation() {
var allValid = true;
if (typeof Page_Validators != 'undefined') {
// Loop through from high to low to capture the base level of error
for (i = Page_Validators.length; i >= 0; i--) {
if (Page_Validators[i] != null) {
if (!Page_Validators[i].isvalid) { // The Control is NOT Valid
$("#" + Page_Validators[i].controltovalidate).removeClass("makeMeGreen").addClass("makeMeRed");
allValid = false;
} else { // Control is valid
$("#" + Page_Validators[i].controltovalidate).removeClass("makeMeRed").addClass("makeMeGreen");
};
};
};
};
}
This will loop through all controls on the page that have an ASP.NET validator attached, and then add or remove a class depending if they are valid or not.
Obviously from here you can limit the function to a specific control by matching the controlToValidate property, and you can restyle, add controls, change classes but this should hopefully provide you a decent base to work from.
I am using the following script to change the HTML5 required attribute of my input elements. I am wonder whether there is a way to modify this script to make it also work in Safari browsers, since Safari does not support this attribute.
Here is the script:
$(document).ready(function() {
$_POST = array();
var elements = document.getElementsByTagName("INPUT");
for (var i = 0; i < elements.length; i++) {
elements[i].oninvalid = function(e) {
e.target.setCustomValidity("");
if (!e.target.validity.valid) {
e.target.setCustomValidity("This field can't be blank");
}
};
elements[i].oninput = function(e) {
e.target.setCustomValidity("");
};
}
})
You can also do this:
var valid = true;
$('input[required]').each(function() {
if (this.value == '') {
// Alert or message to let them know
valid = false;
return false; // stop on first error, or remove this and it'll go through all of them.
}
});
if (valid === false) {
return false;
}
Check out this page here. It contains a hacky solution that should add the desired functionality
http://www.html5rocks.com/en/tutorials/forms/constraintvalidation/#toc-safari
You're going to need to run the check yourself using an event handler on your form submission. In that handler, you run the check yourself, and if it fails, you display whatever error message and block the submission using preventDefault or return false.
An example can be found here, though as it notes, you need to be careful if you use checkValidity as your means of checking the form.
I am trying to get checked options from a table which are set inline. There is a search function, which sets $(element).css('display','none') on objects in which there is no match with the search. Anyways, this piece of code will only return inline, no matter what the elements are set to. Even if I manually set all of them to display: none in the table itself, the alert will return inline for every single object in the table. Is there any solution to this?
JS code:
function pass_QR() {
var i = 0;
var array = [];
$("input:checkbox:checked").each(function () {
i++;
alert($(this).css('display'));
if ($(this).val() !== 0 && $(this).css('display') === 'inline') {
array.push($(this).val());
}
});
}
Fundamentally, css("display") does work, so something else is going on.
I suspect one of two things:
The checkboxes that you're making display: none are never checked, and so you don't see them in your each loop.
You're not making the checkboxes display: none, but instead doing that to some ancestor element of them. In that case, $(this).is(":visible") is what you're looking for.
Here's an example of #2: Live Copy | Live Source
<div id="ancestor">
<input type="checkbox" checked>
</div>
<script>
$("#ancestor").css("display", "none");
console.log("display property is now: " +
$("input:checkbox:checked").css("display"));
console.log("visible tells us what's going on: " +
$("input:checkbox:checked").is(":visible"));
</script>
...which outputs:
display property is now: inline-block
visible tells us what's going on: false
Applying that to your code:
function pass_QR() {
var i = 0;
var array = [];
$("input:checkbox:checked").each(function () {
i++;
alert($(this).css('display'));
if ($(this).val() !== 0 && $(this).is(':visible')) {
// Change is here -----------------^^^^^^^^^^^^^^
array.push($(this).val());
}
});
}
Side note: Every time you call $(), jQuery has to do some work. When you find yourself calling it repeatedly in the same scope, probably best to do that work once:
function pass_QR() {
var i = 0;
var array = [];
$("input:checkbox:checked").each(function () {
var $this = $(this); // <=== Once
i++;
alert($this.css('display'));
if ($this.val() !== 0 && $this.is(':visible')) {
// Other change is here -------^^^^^^^^^^^^^^
array.push($this.val());
}
});
}
try following:
$("input:checkbox:checked").each(function(i,o){
console.log($(this).css("display"));
});
working fiddle here: http://jsfiddle.net/BcfvR/2/
Anyone know of a good tutorial/method of using Javascript to, onSubmit, change the background color of all empty fields with class="required" ?
Something like this should do the trick, but it's difficult to know exactly what you're looking for without you posting more details:
document.getElementById("myForm").onsubmit = function() {
var fields = this.getElementsByClassName("required"),
sendForm = true;
for(var i = 0; i < fields.length; i++) {
if(!fields[i].value) {
fields[i].style.backgroundColor = "#ff0000";
sendForm = false;
}
else {
//Else block added due to comments about returning colour to normal
fields[i].style.backgroundColor = "#fff";
}
}
if(!sendForm) {
return false;
}
}
This attaches a listener to the onsubmit event of the form with id "myForm". It then gets all elements within that form with a class of "required" (note that getElementsByClassName is not supported in older versions of IE, so you may want to look into alternatives there), loops through that collection, checks the value of each, and changes the background colour if it finds any empty ones. If there are any empty ones, it prevents the form from being submitted.
Here's a working example.
Perhaps something like this:
$(document).ready(function () {
$('form').submit(function () {
$('input, textarea, select', this).foreach(function () {
if ($(this).val() == '') {
$(this).addClass('required');
}
});
});
});
I quickly became a fan of jQuery. The documentation is amazing.
http://docs.jquery.com/Downloading_jQuery
if You decide to give the library a try, then here is your code:
//on DOM ready event
$(document).ready(
// register a 'submit' event for your form
$("#formId").submit(function(event){
// clear the required fields if this is the second time the user is submitting the form
$('.required', this).removeClass("required");
// snag every field of type 'input'.
// filter them, keeping inputs with a '' value
// add the class 'required' to the blank inputs.
$('input', this).filter( function( index ){
var keepMe = false;
if(this.val() == ''){
keepMe = true;
}
return keepMe;
}).addClass("required");
if($(".required", this).length > 0){
event.preventDefault();
}
});
);