why after the 3rd click my function doesn't work? - javascript

I have the following html code:
<?php foreach ($this->tags as $uri=>$tag){?>
<input type="checkbox" name="tags[]" style="display: none;" value="<?php echo $uri;?>" id="create_<?php echo $uri;?>" <?php echo isset($args['tags']) && in_array($uri, $args['tags'])?'checked="checked"':'';?> />
<span onclick="selectTag(this.id)" id="create_<?php echo $uri;?>" for="create_<?php echo $uri;?>" class="tag <?php echo isset($args['tags']) && in_array($uri, $args['tags'])?'selected':'';?>"><?php echo str_replace(' ', ' ', $tag);?></span>
<?php }?>
And here is my JS code:
function selectTag(id) {
var input = '.tags input#'+id;
var span = '.tags span#'+id;
if ($(input).is(':checked') && $(span).hasClass('selected')) {
$(span).removeClass('selected');
$(input).attr('checked', false);
}
else {
$(span).addClass('selected');
$(input).attr('checked', true);
}
}
When I click on a span box, selects the box, and when I click again on it, it unselects it. The problem is, that after the 3rd time, it just stops working.
What is wrong with my code that is not working?

JQuery now has a prop method that is a slightly better alternative to using the attr method.
Try replacing your calls with attr("checked", true); with calls to prop("checked", true);
See here for documentation on prop: http://api.jquery.com/prop/
Here for a discussion between the two: .prop() vs .attr()
Edit:
Also, as Ed Cottrell stated, you'll want to have UNIQUE id attributes for all your elements on your page.
Edit2:
I have created a fiddle that demonstrates this usage: http://jsfiddle.net/xDaevax/E39hc/

You are giving the input and the span the same id attribute. Ids must be unique per element; you cannot have an input and a span the same id. Doing it this way will cause all sorts of problems, including the behavior you are experiencing. Give one of them a slightly different id (like create_<?php echo $uri;?>_span).
Also, as #xDaevax says, you should use .prop rather than .attr -- I have had the same problem when using .attr.

Related

The first table row (dynamically generated) always shows, no matter the input value for Javascript

Sorry for asking, I am probably missing something small here but have no clue. I dynamically generated a long list of radio buttons using PHP. On top of the list is an HTML input to search through the list using jQuery. This works, except for one tiny detail. The first radio button in the list always shows, no matter what the search result is. Even if I type something completely different, I will always see the first radio button in the list together with the matching results.
What is going wrong here?
This is my dynamically generated list of radio buttons, using HTML and PHP:
<input id="addplantSearch" class="form-control" type="text" name="addplantsearch" placeholder="Zoek op (Latijnse) naam..." style="margin:0; height:48px;"> <!-- Search input -->
<?php
$query = "SELECT * FROM plants ORDER BY plants.name ASC;";
$post_data = $data->execute($query);
// Prepared statement in 'execute' method (Database class)
?>
<div class="addplant-list">
<?php
foreach ($post_data as $post) {
# Loop start
?>
<div class="searchable">
<label class="pselect-container"> <?php echo $post['name']; ?>
<input type="radio" name="selectPlant" value="<?php echo $post['plant_id']; ?>">
<span class="pselect-checkmark" style="width:100%;">
<img src="../system/src/img/plants/<?php echo $post['directory']; ?>/icon.png" />
<?php echo $post['name'] . " - (" . $post['name_latin'] . ")"; ?>
</span>
</label>
</div>
<?php
# Loop end
}
?>
</div>
And this is my jQuery, responsible for searching through the list:
$("#addplantSearch").keyup(function() {
var value = this.value;
$(".addplant-list").find(".searchable").each(function(index) {
if (!index) return;
var id = $(this).find("span").first().text();
$(this).toggle(id.indexOf(value) !== -1);
});
});
EDIT: The first item in the list is determined by the alphabetical order (ASC) of my database results (see $query variable). So this is always the same item in alphabetical order.
It looks like your issue is with your if statement.
if (!index) return;
This problem occurs because JavaScript uses 0 based arrays, and 0 is also a falsy value. Meaning:
!0 === true
and the first item in the array will always return out of the function and won't be applicable to the toggle logic.
So probably a lot of ways to work around this, one would be to check the length of the array before the each function. Ex:
$("#addplantSearch").keyup(function() {
var value = this.value;
var searchableItems = $(".addplant-list").find(".searchable");
if (searchableItems.length) {
searchableItems.each(function(index) {
var id = $(this).find("span").first().text();
$(this).toggle(id.indexOf(value) !== -1);
});
}
});

PHP doesn't see new elements created with jQuery and AJAX

I faced an issue since I can't get a just created element with a PHP script.
I have a list of tags loaded with PHP:
<ul>
<li>
<input class="adm-checkbox" type="checkbox" name="check_list_tags[]" value="4">
Some tag
<li>
<ul>
Thanks to AJAX I append another element inside the UL
jQuery(document).ready(function($) {
$('.add-tag-btn').click(function(event) {
var tag_title = $('.tag-search').val();
$.ajax({
url: 'add-tag.php',
type: 'POST',
dataType: 'json',
data: {
'tag_title': tag_title
},
success:function(result){
$('.tag-search').val('');
$('.new-tags').append('<li><input class="adm-checkbox" type="checkbox" name="check_list_tags[]" value="'+result.tag_id+'">'+tag_title+'</li>');
console.log(result.tag_id);
}
});
});
});
Thus I have a new UL
<ul>
<li><input class="adm-checkbox" type="checkbox" name="check_list_tags[]" value="4">Value #4</li>
<li><input class="adm-checkbox" type="checkbox" name="check_list_tags[]" value="5">Value #5 (new value generated with jQuery and AJAX)</li>
</ul>
But once I submit the form, only the existed value is added to DB.
if (isset($_POST['submit'])) {
....
bla bla bla
foreach ($_POST['check_list_tags'] as $value) {
$arr2[] = $value;
}
bla bla bal
}
Looks like that PHP can't handle a new value without the page reloaded. At the same time, I add
checked="checked"
dynamically and that works just perfect.
Can anyone explain me how to force PHP to see the newly created elements (the elements that were appended to the existed HTML by the means of jQuery).
Thanks everyone for the assistance.
upd:
This is how I add the "checked"
jQuery(document).ready(function($) {
$('.adm-checkbox').click(function(event) {
if (this.checked) {
this.setAttribute("checked", "checked");
console.log('checked');
} else {
this.removeAttribute("checked");
}
});
});
This is how the form looks like:
<form class="" action="<?php echo $router->url ?>" method="post" enctype="multipart/form-data">
.....
<ul class="new-tags">
</ul>
<ul>
<?php foreach ($admin->getAdmTags() as $value): ?>
<li><input class="adm-checkbox" type="checkbox" name="check_list_tags[]" value="<?php echo $value['id'] ?>"><?php echo $value['title'] ?></li>
<?php endforeach; ?>
<ul>
</form>
UPD # 2:
May be the reason is that I use two separate functions in jQuery for "checked"??!?!
$('.adm-checkbox').click(function(event) {
if (this.checked) {
this.setAttribute("checked", "checked");
console.log('checked');
} else {
this.removeAttribute("checked");
}
});
and
$('.adm-tags').on('click', '.adm-checkbox', function(event) {
if (this.checked) {
this.setAttribute("checked", "checked");
console.log('checked');
} else {
this.removeAttribute("checked");
}
});
I do it because onclick doesn't work for the newly created elements.
P.s: It doesn't matter where I put a newly created "li"...
Thank everyone for participation. I've created a new page and did everything again. And now it works. Now I need to find the mistake in my full code.
Name attributes can be arrays so the name isn't the issue - HTML input arrays
I think the reason is as you mentioned, the checked attribute needs to be added to all of the inputs otherwise the value won't be sent in the request.
If the inputs were text or number for example, then the checked attribute wouldn't be needed.
The same would apply to radio inputs, or the selected attribute for a select menu.
TLDR, add checked:
$('.new-tags').append('<li><input class="adm-checkbox" type="checkbox" name="check_list_tags[]" value="'+result.tag_id+'" checked>'+tag_title+'</li>');
That is of course, if it should be automatically checked and not reliant on the user checking it manually.
I may have to change this answer based on if this is a traditional form submission or an ajax submission not using a form.
I don't know how to close the topic. It works with the newly created code. Once I find out the mistake in my full code, I will reply with the explanation of my mistake.
When you send a form though either POST or GET every input needs a unique name. From you code it looks like you add a new input element with a name attribute that has the same value as the already existing element.
I suspect if you add the new element with a unique name value it should work. You could incorporate that into you JavaScript code by having a counter for the number of input elements with name X and then add a number. And you would need to do a similar thing in your PHP.
Edit: Apparently you can have name attributes with the same name if you use '[]' after the name, thank you #martincarlin87

How to get either select .val() or div .text() from dynamically created elements with same id?

Depending on the user type, my page dynamically creates either a select element (for admins to change) or a div with text (for regular users) using the same id.
if ($user_type == 'admin') {
echo "<tr><td>Type:</td><td><select id='type' >";
echo "<option value='student' >student</option><option value='teacher' >teacher</option>";
echo "</select></td></tr>";
}
else echo "<tr><td>Type:</td><td><div id='type'>" . $user_type . "</div></td></tr>";
When the page submits, I need either the .val() from the select element or the .text() from the div element.
I can't use .val() on the div element and I can't use .text() on the select element.
Is there a way in jQuery / javascript to get one or the other, depending on which element type was created?
make the else statement as so (use input[type=hidden], to use the .val())
else echo
"<tr>
<td>Type:</td>
<td>
<!-- div to show the value -->
<div>$user_type</div>
<!-- hidden input type to get the value via jQuery .val() -->
<input type='hidden' id='type' value='$user_type'>
</td>
</tr>";
Oh by the way, you can use PHP variables inside strings that are defined with double quotes echo "$someVar";
Since you are printing out from PHP the HTML out put, by the same time you can print a Javascript variable who has what method use to get the value/text. Then, use the variable in your Javascript to perform one query or other.
Something like :
if ($user_type == 'admin') {
echo "<tr><td>Type:</td><td><select id='type' >";
echo "<option value='student' >student</option><option value='teacher'>teacher</option>";
echo "</select></td></tr>";
echo "<script> var method = 'val'</script>";
}
else
{
echo "<tr><td>Type:</td><td><div id='type'>" . $user_type . "</div></td></tr>";
echo "<script> var method = 'text'</script>";
}
You can check it with the following simple code in javascript:
if(document.getElementById("type").tagName == "SELECT") {
//Your code for admin
}
else
{
//Your code if it is not admin
}
You can have the text or the value with a simple and elegant ternary condition :
var result = $("#type").val() !== undefined ? $("#type").val() : $("#type").text();

get href from php and use element in JQuery

I have xyz.php and working menu <li> elements. I need to get hreffrom php use it in Java script for navigate away. So I have list of li tag and in code it's displaying one for example. Each li tag has unique href.
My question is: If I have select only one li elements from the list. I want to use that li's associated href in IF condition in JavaScript and ELSE part is multiple Li's selected. The code is working for else part. But, I am having issue with IF part.
I am not getting the href value from PHP. you can get 'href'from $xyz['url'] in php.
xyz.php
<div class="global-wrapper">
<ul class="list">
<li>
<input id="retreat-<?php echo $xyz['api_id']; ?>" class="custom-check-input more-filter-experience" type="checkbox" value="<?php echo $xyz['name']; ?>" data-home-location="<?php echo $xyz['api_id']; ?>">
<label class="custom-check-label" for="retreat-<?php echo $xyz['api_id']; ?>"></label>
</li>
</ul>
</div>
Here, the java script code:
xyz.js
if(retreatIdArray.length === 1 && exploreDate === undefined) {
var categoryId = $('.global-wrapper').find('.loadProducts').attr('data-categoryid');;
window.location.href = "/categoryId"; // having issue
} else{
window.location.href = '/destination';
}
You wrote undefine instead of undefined. The statement inside if will never be true.
Also, to check for undefined, it's better to use typeof.
if(retreatIdArray.length === 1 && typeof exploreDate == 'undefined') {
retreats = $('.global_wrapper').find('.custom-check-input').val();
window.location.href = '/href';
} else {
window.location.href = '/destination';
}
Note: untested code, you may have to adjust it to your needs. Please let me know if it works.

javascript display and hide div element

I am new to Javascript, and I currently have an article that is being fetched from database, the article has two rows. title & content there are about 100 of these in my database. Now the objective is to list all the titles first, and when a user clicks on a title, to make the the relevant content appear underneath it. I can do this however this way.
<?php
//mysql query here...
foreach($result as $row) { ?>
<div id='title'> <?= $row['title'] ?> </div>
<div id='<?= $row['id'] ?>' style='display:none'
onclick=showContent(<?= $row['id'] ?>) > <?= $row['content'] ?>
</div>
<?php } ?>
The javascript to hide the show the content is this:
<script type='text/javascript'>
function showContent(id){
document.getElementById(id).style.display='inline';
}
</script>
The showContent() function hides the div based on the id passed through the paramenter.
But, the only problem is that, I need other previously displayed divs to truntate when a new one opens.
Meaning, the content should be visible only once, then when you click on another title, the previously opened content should disappear and only the new content should appear.
I hope that made sense. as I am lacking the grammar to explain it all. I tried to give small example here, which for some reason does not seem to work at all, but does in my localhost http://jsfiddle.net/YL6aH/
EDITED:
My full PHP loop, together will all the js/html
<?php
$articlesForPreview = $createQuery
->query("SELECT * FROM timeline");
$fetchAll = $articlesForPreview->fetchAll(PDO::FETCH_ASSOC);
foreach($fetchAll as $row) {?>
<div id='timeline_container'>
<span class='timeline_date'> <?= $row['time'] ?></span>
<span class='timeline_title'> <a href='#' onclick=timeline(<?= $row['id'] ?>)><?= $row['title'] ?></a></span>
<p id='<?= $row['id'] ?>' style='display:none;'> <?= $row['event'] ?></a></span>
</div>
<?php }?>
</aside>
</section>
<script type='text/javascript'>
function timeline(id){
document.getElementById(id).style.display='inline';
}
</script>
<footer id='footer_container'>
You can simply remember the last item that is visible:
var active;
function showContent(id){
if (active) active.style.display = 'none'; // hide previously visible element
active = document.getElementById(id); // keep track of the element you are about to show
active.style.display='inline'; // show the new element
}
Keep in mind that this solution starts with no items visible and after that only allows one item to be visible at a time.
You should try this :
function showContent(id){
$('.active').hide().removeClass('active');
$('#'+id).show().addClass('active');
}
I see also that you will have multiple elements with id=title, you must change it to make every elem unique.
You can go through all elements with an onclick of "showContent", hide them all, afterwards you can just show the one you want.
function showContent(id){
var allElements = document.getElementsByTagName('*');
for ( var i = 0; i<allElements.length; i++ ) {
if ( (allElements[i].onclick + "").indexOf("showContent") >= 0) {
allElements[i].style.display = "none";
}
}
document.getElementById(id).style.display='inline';
}
I'm pretty new to javascript and jquery myself, but one of the things we just did in the class I'm taking was the accordion display, where you attach event handlers in the document.ready for the click events for the header objects, and their div children elements, and it was done by swapping the css classes on the click events... are you using css? in our version, anytime we clicked on a plus, it would expand the display to display the divs below, and clicking the minus pic it would close them... ours did it for all of them, but you should be able to code that even to "close" all of those displays, and then open/display only the divs that are children for the item clicked... is that what you're looking for?

Categories

Resources