How to hide a row of table (or a list item) and update the datastore without reloading the page?
I have a list of bookmarks displayed on a table. I added a "hide" link to hide a bookmark that I don't want to see on the list but I still want to keep (table and the hide link show only if you are logged in).
Now I do it by getting the item from the database and by changing its "display" property to "False" and by rendering the page again.
I think this can better be done with javascript without reloading the page. I found several references to hide a row of a table but more than hiding I also need to write the new display property to the database. I don't understand how I can do this. What is the best way to do hide the row and write new display property to the database? Thanks.
This is the code I have now:
#-----------main table------------#
display = self.request.get("display")
main_id = self.request.get("main_id")
self.response.out.write("""<table class="mytable">
<tr class="head">
<th width="80%">links</th><th>edit tags</th>
</tr>
""")
if display == "false":
k = Main.get_by_id(int(main_id))
k.display = False
k.put()
self.redirect("/useradminpage")
query = Main.all()
query.filter("owner", user)
query.filter("display", True)
query.order("-date")
cursor = self.request.get("cursor")
if cursor: query.with_cursor(cursor)
e = query.fetch(100)
cursor = query.cursor()
for item in e:
main_id = item.key().id()
self.response.out.write("""
<tr>
<td><a href="%s" target="_blank">%s</a><span class=small> (%s) </span><br />
<span class=small>%s</span>
<a href="/edit?main_id=%s"><span class="small">(edit)</span></a>
<a href="/useradminpage?main_id=%s&display=false"><span class="small">(hide)</span></a>
<a href="/comment?main_id=%s"><span class="small">(comments)</span></a>
<td><a href="/tc?url=%s&main_id=%s&user_tag_list=%s" title="edit tags">%s</a></td>
</tr>
""" %
tuple([item.url,
item.title,
urlparse(item.url).netloc,
f1.truncate_at_space(item.pitch),
main_id,
main_id,
main_id,
item.url,
main_id,
(", ".join(item.tag_list)),
(", ".join(item.tag_list)),
]))
self.response.out.write("""</table>""")
Update
Trying style.display
in RobG's answer; but the following code does not work:
...
for item in e:
main_id = item.key().id()
self.response.out.write("""
<div>
<tr>
<td><a href="%s" target="_blank">%s</a><span class=small> (%s) </span><br />
<span class=small>%s</span>
<a href="/edit?main_id=%s"><span class="small">(edit)</span></a>
<a href="/useradminpage?main_id=%s&display=false" onclick="this.parentNode.style.display = "none";><span class="small">(hide)</span></a>
<a href="/comment?main_id=%s"><span class="small">(comments)</span></a>
<td><a href="/tc?url=%s&main_id=%s&user_tag_list=%s" title="edit tags">%s</a></td>
</tr>
</div>
...
UPDATE
Trying RobG's edited answer. In this case, when I click the hide button, the row is hidden for a moment and then it is back again. I don't understand why. I paste below the code including the holding table:
#-----------holding table start--------#
self.response.out.write("""
<table border="0" cellpadding="5" cellspacing="10" >
<tbody>
<tr>
<td>""")
self.response.out.write("""<td style="vertical-align:top">""")
#-----------tags table start--------#
self.response.out.write("""<table class="mytable">
<tbody>
<tr class="head">
<th>tags<br />
<a href="/useradminpage?order=alpha"><span class=small>alpha</span></a><br />
<a href="/useradminpage?order=date"><span class=small>newest</span></a><br />
<a href="/useradminpage?order=popular"><span class=small>popular</span></a>
</th>
</tr>
""")
if order_by == "popular":
for tag in most_used:
self.response.out.write("""
<tr><td><a href="/tag?tag=%s">%s</a></td></tr>
""" %
(tag, tag))
else:
for tag in unique_tags:
self.response.out.write("""
<tr><td><a href="/tag?tag=%s">%s</a></td></tr>
""" %
(tag, tag))
self.response.out.write("""</table>""")
#holding table first column end
self.response.out.write("""</td>""")
#holding table second column start
self.response.out.write("""<td style="vertical-align:top">""")
#-----------main table------------#
display = self.request.get("display")
main_id = self.request.get("main_id")
self.response.out.write("""<table class="mytable">
<tr class="head">
<th width="80%">links</th><th>edit tags</th>
</tr>
""")
query = Main.all()
query.filter("owner", user)
#query.filter("display", True)
query.order("-date")
cursor = self.request.get("cursor")
if cursor: query.with_cursor(cursor)
e = query.fetch(100)
cursor = query.cursor()
for item in e:
main_id = item.key().id()
self.response.out.write("""
<tr>
<td><a href="%s" target="_blank">%s</a><span class=small> (%s) </span><br />
<span class=small>%s</span>
<a href="/edit?main_id=%s"><span class="small">(edit)</span></a>
<a href="/useradminpage?main_id=%s&display=false"
onclick="this.parentNode.parentNode.style.display = 'none';">
<span class="small">(hide)</span></a>
<a href="/comment?main_id=%s"><span class="small">(comments)</span></a>
<td><a href="/tc?url=%s&main_id=%s开发者_Python百科&user_tag_list=%s" title="edit tags">%s</a></td>
</tr>
""" %
tuple([item.url,
item.title,
urlparse(item.url).netloc,
f1.truncate_at_space(item.pitch),
main_id,
main_id,
main_id,
item.url,
main_id,
(", ".join(item.tag_list)),
(", ".join(item.tag_list)),
]))
self.response.out.write("""</tbody></table>""")
#holding table end
self.response.out.write('<a href="/useradminpage?cursor=%s">More Results</a>' % cursor)
self.response.out.write("""</td></tr>""")
self.response.out.write("""</tbody></table>""")
self.response.out.write("""</div>""")
You've tagged this as javascript but I don't see any script in the page. I also don't see a table or a "hide" link.
To hide an element and all it's child nodes, set its style.display
property to "none", e.g.
<div>here is some content
<button onclick="this.parentNode.style.display = 'none';">Hide</button>
</div>
Of course if you want to show it again then you'll need a reference to it so you can do:
element.style.display = '';
You can send an HTTP request to the database to update the display value using a variety of methods, AJAX (i.e. using an XMLHttpRequest object) is popular.
Edit
Based on your reply, you want something like this in your page (note the change from dobule to single quotes in the handler and since you want to hide the entire row, you need to go up from the link to the TD, then to the TR):
<table>
<tr>
<td><a href="..." target="_blank">...</a><span class="small">(...)</span><br>
<span class=small>%s</span>
<a href="/edit?main_id=%s"><span class="small">(edit)</span></a>
<a href="/useradminpage?main_id=%s&display=false"
onclick="this.parentNode.parentNode.style.display = 'none'; return false;">
<span class="small">(hide)</span></a>
<a href="/comment?main_id=%s"><span class="small">(comments)</span></a>
<td><a href="/tc?url=%s&main_id=%s&user_tag_list=%s" title="edit tags">%s</a></td>
</tr>
</table>
Incidentally, the closing tags for TR and TD are optional too, which is why the missing closing tag for the first cell doesn't cause any issues.
Edit 2
The "full-blown" fix is to have the "hide" link use a real URL that hides the bookmark by doing the trip to the server. Then use a DOM ready or onload handler to add a listener to all the "hide" links that:
- hides the element (as shown above)
- sends a request to the server to update the status (HTTP request)
- cancels the navigation (returns false)
That way your page works with or without script.
Here's the whole thing:
// Helper to get the text inside an element
function getText(el) {
// If textContent is supported, use it
if (typeof el.textContent == 'string') {
return el.textContent;
}
// Otherwise if innerText is supported, use it
if (typeof el.innerText == 'string') {
return el.innerText;
}
}
// Function that is attached as a listener
// and does the hiding
var hideRow = (function() {
// Store an image in a closure, used for HTTP request
var img = new Image();
// This is the actual function assigned to hideRow
return function (e) {
// Get a reference to the element that called the function
e = e || window.event;
var el = e.target || e.srcElement;
var src;
// Go up the DOM, get the link href for sending
// request and then hide the TR
while (el.parentNode && el.parentNode.tagName) {
el = el.parentNode;
// Get the link on the way and store its href value
if (el.tagName.toLowerCase() == 'a') {
src = el.href;
}
// When get to the TR, send request and
// hide the row
if (el.tagName.toLowerCase() == 'tr') {
el.style.display = 'none';
// Send request, using fake image but could use
// XMLHttpRequest
img.src = src;
// Cancel navigation
return false;
}
}
}
}());
// Adds the above listener to all links that have
// the text "(hide)" in them (case insensitive)
function addListeners() {
// Get all the links in the document
var link, links = document.links;
// A regular expression to match "(hide)"
var re = /\(hide\)/i;
// For each link...
for (var i=0, iLen=links.length; i<iLen; i++) {
// Use a variable for the current link, a bit more efficient
link = links[i];
// If the link contains the text "(hide)"
// add on onclick listener
if (re.test(getText(link))) {
link.onclick = hideRow;
}
}
}
// Call the add listener function when content is loaded
// Could just add in a script element at the bottomo of
// the page immediately before the closing body tag
window.onload = function(){
addListeners();
}
There's nothing App Engine specific here - you just need to make an AJAX request to your app to set the appropriate flag. JQuery is a pretty invaluable library for making this sort of work much simpler on the client end. On the server end, you just need a handler that gets the value to modify in a POST request, then modifies it and returns a status code. Your client side code can call that from AJAX.
精彩评论