How to connect clickable row to specific data sections retrieved from database? - javascript

The title might be a little misleading but it's quite a difficult one to put into words.
I've been trying all day and failed even with attempts from stackoverflow, so I must ask once again for help.
I am retrieving a list of article information from MySQL and displaying them in a table. Once displayed these table rows are clickable by using jQuery .click function, when clicked ckeditor (which is with a display:none;) opens from a <section></section> and hides the whole table.
The issue that I am having is when I click on a row, it should display the data from those specific articles inside the ckeditor, but no matter what the first row data always shows up even if I click on a different row, I can point out that it is due to not having an id so the .click function cannot distinguish which section it is trying to show, but I cannot figure out how to connect the table with the section information.
This is how I am retrieving the data and displaying it in a table, using foreach.
<?php
$getInfo = $articleClass->get_all_article_info();
foreach($getInfo as $data)
{
$article_title = $data['article_title'];
$article_content = substr(htmlentities($data['article_content']),0,50).'...';
$article_content_full = $data['article_content'];
$article_uid = $data['article_uid'];
echo '
<tr id="tr_id" class="'.$article_uid.'">
<td class="marker">
<i class="fa fa-align-left"></i>
</td>
<td class="title">
'.$article_title.'
</td>
<td class="content">
'.$article_content.'
</td>
</tr>
<section id="post_info_id" style="display:none;">
<textarea id="editor1">
<div style="width:468px;">
'.$article_content_full.'
</div>
</textarea>
</section>
';
}
?>
And this is the click function; jQuery.
<script type="text/javascript">
$(document).on('click', '#tr_id', function ()
{
$("#post_info_id").css("display", "block");
$("#table_id").hide();
});
window.onload = function()
{
CKEDITOR.replace( 'editor1' );
};
</script>
I know that the problem is that when I click on the tr, it cannot distinguish the #post_info_id, because it just retrieves about 20 rows of information but the $post_info_id has no specific id to match with the #tr_id, but I have no idea how I could even accomplish this.. I have retrieved the article_uid which is an incremented number when the articles are inserted into the database, and could use that to mark both the #tr_id and #post_info_id but with jQuery I have no idea how to accomplish after what I tried.
I don't want to make this a long question, considering the more I write the less likely I will get an answer but here is what I have tried.
I tried setting the article_uid as the id, but I cannot retrieve the id's of the articles as they're in random, and there's nothing specific that I was able to connect both the post_info_id and tr_id by using .attr('id').

This can be achieved by using the Jquery next() function.
You could change your onclick method to this:
$(document).on('click', '#tr_id', function ()
{
$(this).next('section').css("display", "block");
$("#table_id").hide();
});
And all elements should always have unique ids so here's a way to achieve that:
'<section id="post_info_id"'.$counter.' style="display:none;">
<textarea id="editor'.$counter.'">
<div style="width:468px;">
'.$article_content_full.'
</div>
</textarea>
</section>'
Then declare a variable to keep count outside your loop:
$counter = 0;
Finally, increment the counter at the end of the loop:
$counter++;

Related

JQuery selector, partial DOM searching for performances

I'm actually working with Jquery and at some point I use Jquery selectors to make my page work. The issue here is that the HTML I work with can get very long depending on the data I work with and it looks like this.
HTML
<div class="mailing"></div>
<input type="text" class="mail_subject"/>
<input type="text" class="mail_body"/> <!-- I can have 1 to n number of these -->
<!-- Preview tags -->
<p class='main_subject'></p>
<p class='main_body'></p>
<!--
And a few more things we don't use here
-->
</div>
<div id="table1">
<table id="ranking">
<tbody>
<!-- Data, can have 0 to ~3500 rows -->
</tbody>
</table>
</div>
As you can see, my page is more or less divided in two parts, the <div class="mailing">, which contains a few forms, and the <div id="table1"> that is about displaying lots of data.
In my mailing div I have a few inputs and an auto-updated preview that takes the data from the inputs. What I have here is a kind of "mail builder" with the preview giving me the result with html formatting.
The problem here is about performance, my JQuery is slowed by the table and I got lag when I type in a form and I don't want it to search the whole document as I already know my data will be in the mailing div.
JS
$('.mailing').on('change click keyup keydown', function () {
// Here I append the mail_subject input to the preview
var text = $(this).val();
$('.main_subject').text($('.subject_select').val());
// Here I append each mail_body input to the preview
$('.bodies_select').each(function () {
text = $(this).val();
/*
* Some computation for the text
*/
jQuery('<span/>', {text: text}).appendTo('.main_body');
});
});
I have a few more functions like theses and a few more computation, but I think we got the idea of what my code looks like.
My question is, is there a way, when I use JQuery selectors like $('.main_subject') or $('.bodies_select') to not search the whole DOM document but only in my mailing div for example? The problem is that I can store my elements in variable since it as multiple occasion to be updated.
You can use context with jQuery to improve performances :
$('.bodies_select', '.mailing')
http://api.jquery.com/jquery/#jQuery1
You can even optimize the selectors with some technics :
https://learn.jquery.com/performance/optimize-selectors/
Sure, you just need to place the parent elemenent before
$('.mailing .main_subject')
You should probably read a bit about selectors
https://api.jquery.com/category/selectors/

How to Modify Content in a Text Block

I have some HTML that looks like this:
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
**Text I want to modify**
<span>more content</span>
</td>
targetTD iterates a dynamic number of times depending on the content being rendered. For each iteration, I need to remove a substring of ": " from the beginning of the code in the text block. Unfortunately it's not in its own element and I don't have the ability to wrap it in a neat and tidy id/class. I did some searching and found some js I thought might do the trick:
<script>
var myString = $('.targetTD').html();
myString = myString.replace(': ','');
$('.targetTD').html(myString);
</script>
But that spits out a console error:
Unable to get property 'replace' of undefined or null reference.
Final Update (Solution)
Thanks to #Vaibhav for coming up with a fix! This script did the trick:
<script type="text/javascript">
$(function() {
$('.targetTD').each(function () {
$(this).html($(this).html().replace(/\:\s/g, ''));
});
});
</script>
Update 1
Thanks to #BenM I was able to stop the error from producing by using the following code:
<script>
$(function() {
$('.targetTD').html(function() { $(this).html().replace(': ', ''); });
});
</script>
Although I now don't get an error message, this still isn't removing the ": " from the text block. Any ideas on why this might be?
Update 2
To provide some SharePoint specifics broadly, in response to a comment from #ElvisLikeBear:
The specific task I'm trying to accomplish is hiding the column name from a grouped by list. In SP2010 this was easy to do by hiding the ms-gb class. In 2013, Microsoft has lumped in the expand/collapse button with this class so hiding it wholesale is not an option. I've successfully hid the span with the column name (in my code above, the span wrapped in the a), but the ": " is unhelpfully still in the text block, and now it's just floating there at the beginning of each category name.
The code is being deployed at the page level as a snippet, using the Script Editor web part.
Brendan, issue with your code is you are replacing the ':' with '' but you are not assigning it to the same td again.
Replace(':','') function replaces only first occurance of ':'.Please follow my code. it will replace all the ':' with ''.
With reference from "targetTD iterates a dynamic number of times depending on the content being rendered"
I assume you need foreach loop to iterate over all the Tds.
Html :-
<table>
<tr>
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
Test:Test1
<span>more content</span>
</td>
</tr>
<tr>
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
Test:Test1:test2
<span>more content</span>
</td>
</tr>
<tr>
<td class="targetTD">
<a href="http://foo.com">
<span>content</span>
</a>
Test:Test1:test3:test4
<span>more content</span>
</td>
</tr>
</table>
Jquery :-
<script type="text/javascript">
$(function() {
$('.targetTD').each(function () {
$(this).html($(this).html().replace(/\:/g, ''));
});
});
</script>
Script is tested and works fine.
Make sure the DOM is ready:
<script>
$(function() {
$('.targetTD').html(function() { $(this).html().replace(': ', ''); });
});
</script>
Your tag indicates that this is executing on a SharePoint site which is why your code isn't firing. You need to deploy it properly for SharePoint.
You can do this in a solution or feature, or if it's a one page script you should use a script web part (called the Content Editor webpart in SharePoint 2010 and 2007), you could also add a code snippet to the page in SharePoint 2013.
You could also add the script into the tag via SharePoint designer however I do not believe that would be best practice except in some very specific scenarios (however it would be the easiest approach for a non-SharePoint Devleoper).

jQuery Within a PHP While Loop

I am using jQuery to reveal an extra area of a page when a button is clicked.
The script is
$(document).ready(function() {
$("#prices").on('click', 'a.click', function() {
$(".hiddenstuff").slideToggle(1000),
$("a.click").toggleClass("faded");
});
});
Then the button is
Enquire or Book
and the newly revealed area is
<div class="hiddenstuff" style="display:none">
<!-- HTML form in here -->
</div>
The problem I have is that the button and "hiddenstuff" div are wrapped in a PHP while loop so they repeat anything between one and six times. When the user clicks on one of the buttons, all the hidden divs are revealed. I would like just the hidden div related to the clicked button to reveal.
I presume that I have to create a javascript variable that increments in the while loop and somehow build that into the script. But I just can't see how to get it working.
EDIT, in response to the comments
The while loop is actually a do-while loop. The code inside the loop is about 200 lines of PHP and HTML. That's why I didn't show it all in my question. In a shortened version, but not as shortened as before, it is
do {
<!-- HTML table in here -->
Enquire or Book
<!-- HTML table in here -->
<div class="hiddenstuff" style="display:none">
<!-- HTML form and table in here -->
</div>
<!-- More HTML in here -->
} while ($row_season = mysql_fetch_assoc($season));
EDIT 2
The final solution was exactly as in UPDATE2 in the reply below.
The easiest thing for you to do is to keep your onclick binding but change your hiddenstuff select. Rather than grabbing all the hiddenstuffs which you are doing now, you can search for the next one [the element directly after the specific button that was clicked].
$(this).next('div.hiddenstuff').slideToggle(1000);
UPDATE
i created a fiddle for you with what I would assume would be similar to the output from your php loop. one change from my early answer was rather than using next(), i put a div around each group as I would assume you would have and used .parent().find()
http://jsfiddle.net/wnewby/B25TE/
UPDATE 2: using IDs
Seeing your PHP loop and your nested tables and potentially complex html structure, I no longer thing jquery select by proximity is a good idea [be it by big parent() chains or sibling finds].
So I think this is a case for injecting your ids. I assume your table structure has an id that you can get from $row_season ( $row_season["id"] )
you can then place it in the anchor:
Enquire or Book
and the same for your hiddenstuff
<div class="hiddenstuff" data-rowid=" . $row_season['id'] . " style="display:none">
and then your js can find it easily
$(document).ready(function() {
$("#prices").on('click', 'a.click', function() {
var rowid = $(this).attr("data-rowid");
$(".hiddenstuff[data-rowid='" + rowid + "']").slideToggle(1000),
$(this).toggleClass("faded");
});
});
updated fiddle
If your structure is something like this:
<div class="container">
Enquire or Book
<div class="hiddenstuff" style="display:none">
<!-- HTML form in here -->
</div>
</div>
You can do your js like this:
$(document).ready(function() {
$("#prices").on('click', 'a.click', function() {
$(this).siblings(".hiddenstuff").slideToggle(1000),
$(this).toggleClass("faded");
});
});
which is similar to William Newby answer, but a close look at your while loop, I'd think you could do this:
$(document).ready(function() {
$("#prices").on('click', 'a.click', function() {
var index = $(this).index();
$(".hiddenstuff")[index].slideToggle(1000),
$(this).toggleClass("faded");
});
});
There are several ways of do it, I hope I was useful.

How to reload jquery on onclick event?

I've got a table row where it retrieves data from MySQL and I have included a .onclick function where it opens up a text editor with data inside, but the text editor is only opening for the first row and not the rest in the table.
This is the jQuery code: The first opens the text editor and the second switches the textarea for the text editor which is ckeditor.
<script type="text/javascript">
$(document).ready(function()
{
$(".trClass").click(function()
{
var id = $(this).attr('id');
$('#d_'+id).css("display", "block");
$('#table_id').css("display", "none");
});
});
window.onload = function()
{
CKEDITOR.replace("editor1");
};
</script>
and this here is echo for the table, I am using a foreach.
echo '
<tr class="trClass" id="'.$counter.'">
<td class="marker">
<i class="fa fa-align-left"></i>
</td>
<td class="title">
'.$article_title.'
</td>
<td class="content">
'.$article_content.'
</td>
</tr>
<section id="d_'.$counter.'" style="display:none;">
<textarea id="editor1">
<div style="width:468px;">
'.$article_content_full.'
</div>
</textarea>
</section>
';
$counter++;
}
I cannot figure out how to make the CKEDITOR.replace("editor1"); load for every table, I tried using .click function within it but it does not work as it doesn't load. Here is the problem, if you click on the first row it opens the text editor if you click on the second it does not; http://www.goo.gl/dQrLPN
Typically the id attribute should be unique for each element. Applying properties across multiple elements is usually accomplished with a class. Knowing this, CKEditor is probably just grabbing the first instance of an object with the given id (probably using document.GetElementById behind the scenes).
(According to the documentation, CKEDITOR.replace(var) will either take a DOM element, ID, or name.)
Given that, you have a couple of options. One is to defer loading the CKEditor until you actually click on the table row. This would look something like this... (note how each textarea has a unique id)
<section id="d_' . $counter . '" style="display:none;">
<textarea id="editor_'.$counter.'">
<div style="width:468px;">
'.$article_content_full.'
</div>
</textarea>
$(document).ready(function()
{
$(".trClass").click(function()
{
var id = $(this).attr('id');
$('#d_'+id).css("display", "block");
$('#table_id').css("display", "none");
CKEDITOR.replace('editor_'+id);
});
});
The second option would be to loop through all of the textarea elements and call replace on each one of them on-load. I wouldn't really recommend this, unless there's some specific reason you want to load everything up-front.
EDIT: Although this should fix your issue, you should look in to the HTML issues the other answerers have put forward. <section> doesn't belong as a child of <table> :-)
Try targeting the table and filtering by the rows using the .on() method.
$(document).ready(function()
{
$('#table_id').on('click','.trClass',function() {
var id = $(this).attr('id');
$('#d_'+id).css('display', 'block');
$('#table_id').css('display', 'none');
});
});
Details on .on() are here: https://api.jquery.com/on/
And as noted in the comments above, there are some overall issues with your HTML that you should probably fix before proceeding further.

Putting value into Textbox upon clicking Div

I am currently trying to make a wallpaper changer for my page.
At the minute, I would like to put the URL of a wallpaper into a text box when it's respective DIV option in a CSS menu is clicked.
Here is my JQuery
$("div.bg8").click( function() {
var BackgroundURL = 'Styles/hongkongskyline.jpg';
var TheTextBox = document.getElementById('<%=BackgroundsTxt.ClientID%>');
TheTextBox.value= BackgroundURL;
alert('This has worked'); });
.. and my HTML...
<ul><li class="#cssmenu"><a>
<div id="bg8" runat="server">
<table style="height: 16px; width:33%;">
<tr>
<td>
<img src='Styles/hongkongskyline.jpg' width="34px" height="32px" /></td> <td>Hong Kong Skyline </td>
</tr>
</table>
</div>
</a></li></ul>
Unfortunately, nothing seems to be happening when I click the DIV..
Does anybody see any problems which I can't?
Many thanks.
Several problems here.
First, you aren't referring to your div's ID in your jQuery - you're referring to a class called bg8. Try this:
$("#bg8")...
Next, you're mixing in some native-dom stuff into your jQuery. Instead of
document.getElementById('<%=BackgroundsTxt.ClientID%>');
try
$("#<%=BackgroundsTxt.ClientID%>");
and make sure the ID is resolved by looking at the source to your page.
And lastly, to set the value of the textbox:
theTextBox.val(BackgroundURL);
Your whole function could be
$("#bg8").click( function() {
$("#<%=BackgroundsTxt.ClientID%>").val('Styles/hongkongskyline.jpg');
alert('This has worked');
});
My strategy is to test event handlers with simple alerts before moving on to the real logic.
your jQuery states $('div.bg8') , this calls for a div with the class bg8,
you have not set the class, but rather the id of your div as bg8
change this: $('div.bg8') to $('#bg8')
;)

Categories