I have the following function, which is used to expand and collapse child tr rows from parent rows within a table, and also changes the text style of a tr to normal:
$( document ).ready(function() {
$('.parent').on('click', function(){
$(this).next('.child').toggle();
$(this).css('font-weight', 'normal');
<<< ADD COMMAND TO TOGGLE BUTTON HERE >>>
});
});
I also have the following hidden button within each tr, which I want to submit when a tr is clicked:
<button type="submit" name="read-button" formmethod="POST" value="{{ message.message_id }}" style="display: none;"></button>
Which command should I include alongside the JavaScript function, in order to achieve this? I believe it will be one of the following (provided by this answer), however I've only been using JS for a few days so I'm not sure how to include these in my code:
document.getElementById('read-button').submit();
changeAction('read-button','loginForm');
document.forms['read-button'].submit();
Sample html:
<form method=['POST']>
<table>
<tr class="parent">
<td>
<button type="submit" name="read-button" formmethod="POST" value="{{ message.message_id }}" style="display: none;"></button>
<a>Heres a cell</a>
</td>
<td>
<a>
Heres one more cell
<a>
</td>
</tr>
<tr class="child">
<td>
<a>
Some hidden info
</a>
</td>
<td>
<a>
More hidden info
</a>
</td>
</tr>
<table>
</form>
To answer the specific question of how to trigger a button within a td via clicking on the tr:
$('.parent').on('click', function() {
$(this).find("button").click();
that can be improved by giving the button a class (incase you add additional buttons in future), eg:
<button class='readbutton' ..`
then
$('.parent').on('click', function() {
$(this).find("button.readbutton").click();
In this scenario, it seems that you don't need a hidden button as you can call the functionality of the hidden button directly.
So rather than:
$("button").click(handleClick);
use
$('.parent').on('click', function() {
.. other functionality ...
handleClick();
as you're new to js, note the difference between handleClick and handleClick() - with () it calls the function, without it passes it as a function variable.
$("button").click(handleClick);
is the same as
$("button").click(function() { handleClick(); });
If you're trying to submit a form, then you would use $(form).submit() - but there's no form in the code as pointed out in the comments and an ajax call would seem more appropriate here than submitting a form.
Finally, consider using classes rather than setting the css directly as adding/removing classes it quite simple in jquery eg for your tr click event add:
$(this).addClass("selected").siblings().removeClass("selected");
Related
I have a Razor foreach loop in my MVC view which will generate a number of table rows containing buttons:
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>
<button id="btn" class="button btn-primary" type="button" onclick="location.href='#Url.Action("RunSingleTest", "Home", new {testName=#item.Test_type, id=#item.Id})'"> Run Test</button>
<img id="loading" src="img/ajax-loader.gif" alt="" style="display:none;" />
</td>
</tr>
}
I want to disable button on click and show loading spinner, however this doesn't work the way I do. (it works in my other page when there's single button)
this is my script:
$(function () {
$('#btn').click(function () {
$('#btn').attr("disabled", "true");
$('#loading').show();
});
});
How to make it work in foreach?
Don't use id, use class. $('#btn') will return only the first element that has this id, even if there are more.
Make sure the id's of your elements are unique. According to the html standard you can not have duplicated id's.
I changed your code a bit to fit the snippet and to work better.
Using prop() instead of attr() because it support properties a lot better.
Added an iteration number to the id's in the loop.
Added class to the loading element for a common jQuery/Css selector
used $(this) selector to get the current clicked buttons. Because of this had to use the sublings() function to get the corresponding <img> element.
$(document).ready(function() {
$('.button').on('click', function () {
$(this).prop("disabled", true);
$(this).siblings('.loading').show();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>1</td>
<td>
<button id="btn1" class="button btn-primary" type="button"> Run Test</button>
<img id="loading1" class="loading" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" alt="" style="display:none;" />
</td>
</tr>
<tr>
<td>2</td>
<td>
<button id="btn2" class="button btn-primary" type="button"> Run Test</button>
<img id="loading2" class="loading" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" alt="" style="display:none;" />
</td>
</tr>
<tr>
<td>3</td>
<td>
<button id="btn3" class="button btn-primary" type="button"> Run Test</button>
<img id="loading3" class="loading" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" alt="" style="display:none;" />
</td>
</tr>
</table>
Having multiple buttons (or any other HTML element) with the same ID is not valid HTML. IDs are meant to be unique identifiers of the element - after all, if they weren't they'd no longer be fit to call an "ID"!
Consequently, your "click" handler will only ever be bound to the first element which has that ID. JavaScript is only expecting one matching element, and will not even consider all the others.
You need to use classes instead:
$('.button').click(function () {
will bind to all buttons with the "button" CSS class.
You can then use $(this) to get hold of the current button. You'll need to traverse the DOM to get the nearest "loading" element (which also needs to use ca class instead of an ID).
Also you should use .prop() to set the "disabled" property (note, not attribute!) instead of .attr() as documented here: http://api.jquery.com/attr/
If we add all that together we get something like:
$(function () {
$('.button').click(function () {
$(this).prop("disabled", true);
$(this).siblings('.loading').show();
});
});
in the jQuery, and
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>
<button class="button btn-primary" type="button"> Run Test</button>
<img class="loading" src="img/ajax-loader.gif" alt="" style="display:none;" />
</td>
</tr>
}
BTW in your code you seem to have a jQuery "click" function and an inline "onclick" event handler. This is not good from a maintainability perspective - better to choose a style and stick to it. Also since your "onclick" navigates the user to another page, all other changes you do in the jQuery handler will be lost immediately in any case. I have removed it in the example above, as it's unclear what is purpose really is, or if it's needed.
Try the below code to disable the button.
$(function () {
$('#btn').click(function () {
$(this).prop("disabled",true);
$('#loading').show();
});
});
You can still trigger it by the id's of the buttons, but it has to be done this way:
$('[id^=btn]').click(function () {
$(this).prop("disabled", "true");
$(this).siblings('#loading').show();
});
That will allow the individual button to be disabled when it's clicked and also only show the image that is in relation to the button clicked.
Have several problems and can't find solution. My code https://jsfiddle.net/46qybyrh/2/
Upper table HTML
<div class="block">
<table>
<tr>
<th>Nr.</th>
<th style="width: 200px">Task</th>
<th>Progresas</th>
<th></th>
</tr>
<tr>
<td>1</td>
<td>Air port scedules</td>
<td>0/3</td>
<td>
<button onclick="showDiv()">Expand</button>
</td>
</tr>
</table>
Hidden div
<div id="popup" class="popupbox">
<table class="block">
<tbody>
<tr>
<td></td>
<form>
<td>XML</td>
<td>
<span>Comment</span><br>
<textarea></textarea>
</td>
<td>
<span>Deadline</span>
<input type="date" value="2017-08-24">
</td>
<td>Done:<input type="checkbox"></td>
<td><input type="submit" value="Apply"></td>
</form>
</tr>
<tr>
<td></td>
<form>
<td>Scedules</td>
<td>
<span>Comment</span><br>
<textarea></textarea>
</td>
<td><span>Deadline</span>
<input type="date" value="2017-08-10">
</td>
<td>Done:<input type="checkbox"></td>
<td><input type="submit" value="Apply"></td>
</form>
</tr>
<tr>
<td></td>
<form>
<td>Infobox</td>
<td>
<span>Comment</span><br>
<textarea></textarea>
</td>
<td><span>Deadline</span>
<input type="date" value="2017-08-14">
</td>
<td>Done:<input type="checkbox"></td>
<td><input type="submit" value="Apply"></td>
</form>
</tr>
</tbody>
</table>
<button onclick="hideDiv()">close</button></div>
Main aims of this code should be:
When press apply on each row, hidden div should not hide. Only information like comment, date, check box should change.
When all 3 check boxes are selected, upper tables first row (1 Air port scedules 0/3) should change its background color.
If deadline is close (let say 5 days till deadline) entire row should change background color.
If deadline is passed entire row should change its background color.
I know its a lot to ask but maybe someone of you will guide me on each of this steps.
I took your fiddle and put it into a codepen and messed around with it for a while. I was able to do what you wanted with a lot of jQuery. To learn jQuery, try www.w3schools.com/jQuery.
Here is the codepen:
https://codepen.io/pen/Ojxzje
In a few short steps:
I removed all the <form> tags, <input type='submit'>, and <tbody> to make the code cleaner (the submit button was causing problems with hiding the div as mentioned by #AngeLOL.
I reformatted the lower table a bit just to make it cleaner for my jQuery to work nicely. (I added a header row and removed the text from the blocks)
I included the jQuery library
I renamed your jQuery functions and created one more (open(), close(), and apply(). They are called by the buttons respectively.
Inside the open() function, I showed the rows in the second table with the class if items-[ID OF LIST WE ARE IN]. This way there could be a clean list of all of the tasks instead of having a new table for every new list.
The open() function also changes the button from expand to hide which calls the close function.
The close() function just hides the second table and changes the name of the button back to expand.
The apply() function is run whenever you press the Apply button. It performs two checks:
Checks all of the checkboxes in the table rows labeled .details-[ID WE ARE WORKING WITH] and if they are all checked, selects the list's row in the upper table. It adds a green color to the background.
It then finds all the dates and compares them with today's date (thanks again #angeLOL. If the date is within 5 days, it selects the row the date was on and changes the color. If the date has passed or is today, it colors the row red.
It's a lot of code and a bunch of reorganization, so let me know if you are having trouble understanding it and I can help walk through my steps.
use <button type="button">Apply</button> instead <input
type="submit" value="Apply">
Give to those elements you want to change its color an "id" attribute, so change its color by using style propierty of element
document.getElementById("elementID").style.backgroundColor = "#colorcode"
Here is an example of how to compare dates.
Hidden div is initially hidden. When you submit the form, you reload the page, so it is hidden again. You may want to handle click on button or form submit, prevent default behavior, submit data via AJAX request and then update your UI without page reload.
<form onsubmit="return handleSubmit(this);">
...
<input type="checkbox" onchange="updateCheckboxesState();">
</form>
<script>
function handleSubmit(form) {
// send AJAX request here...
// manipulate DOM if needed in AJAX callback
return false; // prevent submit
}
function updateCheckboxesState() {
var checkboxes = document.querySelectorAll("form input[type=checkbox]");
for (var i = 0; i < checkboxes.length; i++) {
if (!checkboxes.item(i).checked) return; // break on first unchecked
}
// highlight the row here...
}
</script>
Similar flow can be applied to date inputs. The main idea is to update UI when value has been changed.
Background change can be achieved via changing element's inline style or changing it's class
var el = document.querySelector("div.block > table > tr");
el.style.backgroundColor = "#FF0000"; // inline
el.className = "highlighted"; // element class
Hope, this helps...
Firstly a bit of background: I'm modifying Drupal's backend (Node creation form) to dynamically add an html to a dynamically created element.
So, this is not a strictly Drupal question, as I believe what I want to know is within the realm of jQuery rather than Drupal.
In my form, I have a repeater (initially I have 1 textarea element, when I click on 'Add more' I'll have 2 textarea elements, and so on).
What I'd like to achieve is, trigger an event (hide elements, add others) when the 'Add more' button is clicked.
So I wrote this:
(function($) {
'use strict';
$(document).ready(function() {
var $container = $('#edit-field-updates tbody .draggable td div.form-item');
$container.find('textarea').hide();
var select = '<select><option value="template_1">Template One</option><option value="template_2">Template Two</option><option value="custom">Custom</option></select>';
$container.append(select);
$('html').click(function (event) {
$container.find('textarea').hide();
$container.append(select);
});
});
})(jQuery);
Note that the I achieve what I want on page load, which is to modify the element. The problem appears when the user click on 'Add more' to add more items.
PS: Ideally I'd like to post the original code that generates the repeater however I still haven't found it yet. This admin theme is based on the Rubik theme, but its a child theme developed internally by someone who's left so can't figure it out where it is.
I've also tried:
...
$('html').on('click', 'input', function (event) {
alert('OI');
$container.find('textarea').hide();
$container.append(select);
});
...
Which does trigger the alert when I click on the page for the second time (I click on 'Add more', then click again anywhere on the page. I guess because I used 'html' rather than a element), however when I used a specific element rather than 'html' it didn't work.
Any ideas?
EDIT:
I've also tried:
$('#edit-field-updates-und-add-more').click(function() {
$container.find('textarea').hide();
$container.append(select);
});
Which didn't work. Here's the html:
<div class="field-type-text-long field-name-field-updates field-widget-text-textarea form-wrapper" id="edit-field-updates"><div id="field-updates-add-more-wrapper"><div class="form-item"><table id="field-updates-values" class="field-multiple-table sticky-enabled">
<thead><tr><th colspan="2" class="field-label"><label>Updates </label></th><th>Order</th> </tr></thead>
<tbody>
<tr class="draggable odd"><td class="field-multiple-drag"></td><td><div class="form-item form-type-textarea form-item-field-updates-und-0-value">
<div class="form-textarea-wrapper resizable"><textarea class="text-full form-textarea" name="field_updates[und][0][value]" id="edit-field-updates-und-0-value" cols="60" rows="5"></textarea></div>
</div>
</td><td class="delta-order"><div class="form-item form-type-select form-item-field-updates-und-0--weight">
<label class="element-invisible" for="edit-field-updates-und-0-weight">Weight for row 1 </label>
<select class="field_updates-delta-order form-select" id="edit-field-updates-und-0-weight" name="field_updates[und][0][_weight]"><option value="0" selected="selected">0</option></select>
</div>
</td> </tr>
</tbody>
</table>
<div class="clearfix"><input class="field-add-more-submit button-add form-submit" type="submit" id="edit-field-updates-und-add-more" name="field_updates_add_more" value="Add another item"></div></div></div></div>
Use...
$("#AddMoreButton").click(function() {
Your Code Here
});
To add the click event only onto the button rather then the whole page. You can wrap that button .click() function with a document.ready() function so that the click event is set on the button when the page loads.
$(document).ready(function() {
$("#AddMoreButton").click(function() {
Your Code Here
});
});
When you set...
$('html').on('click', 'input', function (event) {...
It causes the entire HTML doc to have the click event set on it.
Things to note: #AddMoreButton corresponds to the ID set on the button so it would look like this.
<button id="AddMoreButton">Add More</button>
I have this inbox or mails which I needed to mark using checkbox for multiple deletions. The problem is that when I click the checkbox it always go to method read() because of onclick inside the tag. All I want is simple marking. Please see the code below:
#foreach ($messages as $message)
<tr onclick="document.location='{{route('account.message.read', array($message->id))}}'">
<td> <input type="checkbox" name="msg" value="{{$message->id}}"></td>
<td><strong>{{Str::words($message->subject, 5, '...')}}</strong> {{Str::words($message->message, 20, '...')}}</td>
</tr>
#endforeach
Now how can I mark each row without going inside that method? I am a newbie btw.
All you need to is attach handler to checkbox and use stopPropagation from bubbling up into trees, see below example :
HTML
Supposed we have table rows with onclick inline javascript and inside it have input:
<table>
<tr onclick="return alert('Hai')">
<td>
<input type="checkbox" />Click Me
</td>
</tr>
<table>
And here the handler :
$('input').click(function(e){
// normally if we removed this line of code
// alert will getting called as checkbox is checked/unchecked
// was inside table rows
// but with this propagation, we disabled it
// from bubbling up into tree
e.stopPropagation();
});
DEMO
you could put the onclick inside the tags excluding the checkbox cell
otherwise you could call an actual onclick function while capturing the click event and check that x is greater than lets say 50px!
<script type="text/javascript">
document.getElementById('emailRow1').addEventListener("click",function(e){
var x=e.pageX-this.offsetLeft;
if(x>50){
rowClicked();
}
},true);
</script>
<table><tbody><tr id='emailRow1'><td style="width:50px;">This area wont trigger onclick</td><td>I trigger onclick</td><td>i trigger onclick</td>
Then you can set custom parameters on your object and recall them using this.customPropertyName to determine what row was clicked! hope this helps
I have some tags (tagbutton) in a table, each tag has its own id, what I want to achieve is when the user clicks on the tag, a hidden input is created in the form with the value of the div (or tag) that has been clicked on. I also want the clicked div to be copied in the tagselected div.
I have no idea how to do that on jquery. Thank you very much in advance for your help.
<table> <tr>
<td> <div class="tagbutton" id="jazz"> Jazz </div> </td>
<td> <div class="tagbutton" id="classical"> Classical </div> </td>
<td> <div class="tagbutton" id="R&B"> R&B </div> </td>
</tr> </table>
<div id="tagselected"> </div>
<form> <input type="text"> <button ="submit"> Submit </button> </form>
Here is the javascript function that I have to copy the div, however when I clicked on it the entire table is copied
$('#jazz').click(function () {
$('.tagbutton').clone().insertAfter("#tagselected");
});
This code is wrong:
$('#jazz').click(function () {
$('.tagbutton').clone().insertAfter("#tagselected");
});
The problem with this code is that you are retrieving all the items with class tagbutton on the whole page. If your click function is on the item you want then you should be able to just use this to access the clicked item.
so something like :
$(this).clone().insertAfter("#tagselected");
This code is not tested and is just the simple change of the initial jQuery selector.
I assume the problem you have with the hidden fields is the same - that you were selcting all tags instead of just the one you clicked so hopefully this will solve that problem too.