I've got the following bit of code (using JQuery) that I've written for a project. The idea is to have a function that you can attach to an element within an "item" div and it will return the id of that div. In this case, the div id would be item-[some item primary key value]. This function works probably 9/10 times, but every once in a while it will get to the else else case and return false. I've verified through the console that the input for selector is the exact same JQuery $() item in both the success and fail cases.
I'm relatively new to JavaScript, so there may be something obvious I'm missing, but this is some really unusual behavior.
var recursionCounter = 0;
function getElementID(selector, recursionDepth, searchString){
console.log(selector);
var elementID = selector.attr("id");
if(elementID === undefined){
elementID = "";
}
if(elementID.indexOf(searchString) !== -1){
elementID = elementID.split("-")[1];
return elementID;
} else {
if(recursionCounter < recursionDepth){
recursionCounter++;
return getElementID(selector.parent(), recursionDepth, searchString);
} else {
recursionCounter = 0;
alert("The element clicked does not have an associated key.");
return false;
}
}
}
Here is an example of code that calls this function, for some context.
$(document).on("click", ".edit-pencil-item", function(event) {
//Use helper function to get the id of the surrounding div then pass it to the function
var itemID = getElementID($(this), 10, "item-");
jsEditItem(itemID);
return false;
});
Thanks in advance for any help!
If you want to get the encapsulating element of your clicked element, and you know it should have an id starting with "item-" you should be able to do something along the lines of
$(this).closest('[id^="item-"]').attr('id')
Which says find this elements closest parent that has an id starting with "item-" and tell me its id.
Related
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.
I have a left sidebar menu which has submenus, i want each menu item to toggle a classname "active" so the submenu will open i have CSS for it.
The thing is i am using document.getElementsByClassName to select and iterate all of the menu items and is only working for the first element, i have been searching and it has something to do with closures and i am trying different solutions but its not working.
i am making the function so i can use it to toggle a classname of another div and not the one clicked, in that case i use and ID.
var toggleClassname = function (otherDiv, sameDiv) {
var divToToggleClass;
//are we going to use ID and toggle the classname of another div ?
if (sameDiv) {
divToToggleClass = this;
} else {
divToToggleClass = document.getElementById(otherDiv);
}
console.log(divToToggleClass);
var className = divToToggleClass.className + ' ';
if (~className.indexOf(' active ')) {
divToToggleClass.className = className.replace(' active ', '');
} else {
divToToggleClass.className += ' active';
}
};
var MenuItemsArray = document.getElementsByClassName("classOfMyMenuItems");
for (var i = 0; i < subMenuItemsArray.length; i++) {
MenuItemsArray[i].addEventListener('click', function () { toggleClassname(null, true) }, false);
}
i have been trying using [].forEach.call or wrapping the function in another that returns the function, not working.
I am doing this in pure javascript, cant use the new .classList.toggle i would also use attachEvent to be more backwards compatible (old IE).
The problem is that within your toggleClassname() function this is not equal to the clicked element. It will actually be either undefined or window depending on whether your code is running in strict mode or not.
A click handler bound with addEventListener() will have this set to the clicked element, so within the following anonymous function:
function () { toggleClassname(null, true) }
...the value of this is the element in question. But then you call toggleClassname() and don't pass it a reference to the clicked element or set its this value. You can explicitly set it using .call():
function () { toggleClassname.call(this, null, true) }
Further reading:
this in JavaScript
.call()
This answer might help you:
addEventListener using for loop and passing values
Without going too deep into your code, I'd say if you try and make it
for (var i = 0; i < subMenuItemsArray.length; i++) {
(function () {
var k = i;
MenuItemsArray[k].addEventListener('click', function () { toggleClassname(null, true) }, false);
}()); // immediate invocation
}
That should work.
So i am having trouble unhiding a div, once it has been hidden.
The code:
First object
$('#filter_region').on('change', function(e) {
var temp_region_id = $('#filter_region').val();
filterRegionId($temp_region_id);
});
Seconds object:
function filterRegionId(temp_region_id)
{
if ($(temp_region_id) != 1) {
$('.showheadline').hide(); }
else { $('.showheadline').show(); }
}
Really what i want to do, is once the region is changed from the original, the div should be hidden - this works!
However, once the person goes back on the same region, the div is still hidden.
The filter_region echos from 1-8 depending on the region. I realise that i have set the region to 1, this is to test. However, even if the if-statement is set to 1, it still shows the divs when loaded, even if the region is 2-8. Hope this make any sense at all! Please feel free to ask if there are any questions regarding my explanation.
Best Regards,
Patrick
Try this, without the $(..) around the var
$('#filter_region').on('change', function(e) {
var temp_region_id = $('#filter_region').val();
filterRegionId(temp_region_id);
});
function filterRegionId(temp_region_id)
{
if (temp_region_id != 1) {
$('.showheadline').hide();
}
else {
$('.showheadline').show();
}
}
A text input's value attribute will always return a string. You need to parseInt the value to get an integer
var temp_region_id = parseInt($('#filter_region').val(),10);
and remove the $ from variable name filterRegionId($temp_region_id); and if ($(temp_region_id) != 1) {
$('#filter_region').on('change', function(e) {
var temp_region_id = parseInt($('#filter_region').val(),10);
///parse it to integer
filterRegionId(temp_region_id);
});
function filterRegionId(temp_region_id){
if (temp_region_id!= 1)
$('.showheadline').hide();
else
$('.showheadline').show();
}
The best solution is to rewrite you code a little.
Please add the filterRegion function on top and change the parametter name as follows
var temp_region_id = $('#filter_region').val();
filterRegionId(temp_region_id);
$('#filter_region').on('change', function(e) {
temp_region_id= $('#filter_region').val();
filterRegionId(temp_region_id);
});
function filterRegionId(temp_region_id)
{
if ($(temp_region_id) != 1) {
$('.showheadline').hide();
}
else {
$('.showheadline').show();
}
}
That's not that great of a title for the question, so if anyone else has a better way to word it after reading it, that'd be appreciated.
Disclosure out of the way, this is homework. The assignment for this week is to refactor our already existing plain JS code to use JQM and I'm having an issue with a conversion I can't quite figure out, here's the code:
function populateItemLinks(key, listItem)
{
var ecLink = $('<a class="padRightRed"></a>');
ecLink.attr("href", "#");
ecLink.attr("key", key);
ecLink.html("Edit Character");
ecLink.on("click", editCharacter);
ecLink.appendTo(listItem);
console.log(ecLink.attr("key"));
ecLink = $('<a class="padLeftRed"></a>');
ecLink.attr("href", "#");
ecLink.attr("key", key);
ecLink.html("Delete Character");
ecLink.on("click", deleteCharacter);
ecLink.appendTo(listItem);
console.log(ecLink.attr("key"));
};
function deleteCharacter()
{
var toDelete = confirm("Do you wish to delete this character?");
if (toDelete)
{
console.log(this.key);
alert("Character was deleted.");
localStorage.removeItem(this.key);
$.mobile.changePage("#home");
}
else
{
alert("Character was not deleted.");
}
}
The issue is the using of the .key attribute as an itentified for the links in the populateItemLinks functions. When it was strait javascript, I could just do linkname.key = key; and then get the key back in the deleteCharacter function with "this.key". Well, now it's always returning undefined and I can't think of any way that wouldn't be convoluted to get the same functionality as the non-JQM version, so any help would be appreciated.
The reason your code is returning undefined is that you're trying to read a property of the DOM element, but you've set an attribute of the DOM element.
The top answers for this question explain the different between the two: .prop() vs .attr()
If you were to set the property of your newly created DOM element like this:
ecLink.prop('key', 12355);
And continued to directly access the DOM element (not via jQuery):
this.key; // 123455
All would of been well. Here is a JSFiddle example showing this in further detail.
Anyway, I've adjusted your code to work with the attribute you're setting:
function deleteCharacter()
{
var toDelete = confirm("Do you wish to delete this character?");
if (toDelete)
{
var key = $(this).attr('key');
alert("Character was deleted.");
localStorage.removeItem(key);
$.mobile.changePage("#home");
}
else
{
alert("Character was not deleted.");
}
}
Having said all this, Data attributes are better suited for storing arbitrary data against a DOM element:
ecLink.data('key', myKey); // set
ecLink.data('key'); // get
What I would do is pass the clicked ecLink as an argument to deleteCharacter() like this:
ecLink.on("click",function() { deleteCharacter($(this)); });
Then you can modify deleteCharacter():
function deleteCharacter(el)
{
var toDelete = confirm("Do you wish to delete this character?");
if (toDelete)
{
var key = el.attr('key'); //get the key attribute
console.log(key);
alert("Character was deleted.");
localStorage.removeItem(key);
$.mobile.changePage("#home");
}
else
{
alert("Character was not deleted.");
}
}
I am trying to debug this (incomplete) script, but it is behaving inconsistently. The main problem is when I click off of an item, sometimes the $(editObj).removeAttr('style'); runs and sometimes not. Through the Chrome inspector I can see that the editObj variable in each case is properly defined, but it isn't always getting its inline style attribute removed. Sometimes, and sometimes not. Cannot determine the reason.
I'm a bit out of my element with this code. Maybe something about it is obvious; Regardless I'd appreciate some ideas on why this sort of unpredictable might be occuring!
var editObj = null;
var inputType = 'text';
var input = '#textEdit';
var formId = '#form_undefined'
$(function() {
$("#textEdit").click(function(event) {
event.stopPropagation();
});
$('body').click(function(event) {
if (editObj){
//textedit contents to editobj and
if (inputType == 'text'){
$(editObj).text($("#textEdit").val());
}
$("#textEdit").removeAttr('style').hide();
$(editObj).removeAttr('style');
var previewId = $(editObj).attr('id');
var formId = previewId.replace('bzm', 'form');
$("#" + formId).val($("#textEdit").val());
//ajax modify database
editObj = null;
}
});
$(".editable").not("video, img, textarea")
.click(function(event) {
event.stopPropagation();
loadEditor($(this));
});
});
function loadEditor(element){
$("#textEdit")
.copyCSS(element)
.offset($(element).offset())
.css("display", "block")
.val($(element).text())
.select();
$(element).css("color", "transparent");
editObj = element;
}
I've had trouble in the past with .removeAttr('style'); not actually removing all the inline styles.
Use
$(editObj).attr('style', '');
instead of
$(editObj).removeAttr('style');
I dint see any code that initializes e editobj variable.. May be Im missing Anthony.. Anyways what are the chances of the edit obj being null.. Just put a log statement in the click function to always log ur editobj and see if it is null smtimes