Using the Jquery closest() function? - closest

Here's my HTML:
<tr>
<td class="show_r3c">click here</td>
</tr>
<tr class="r3c">
<td>This is what I'd like to display</td>
</tr>
And I have currently got this JQuery code,
$(document).ready(function(){
$(".r3c").hide();
$('.show_r3c').click(function() {
$(this).closest('.r3c').toggle();
return false;
});
});
For some reason the closest() function isn't working, and it won't toggle the table row .r3c - I've tried using parent and other alternatives but can't get it working either :(
Apologies for the silly question, and something similar to a problem I've had before. Just wondering, What's the best solution for this ?
Thanks!

closest() finds the closest parent not the parents-siblings-children.
You want something like:
$(document).ready(function(){
$(".r3c").hide();
$('.show_r3c').click(function() {
$(this).closest('table').find("tr.r3c").toggle(); return false;
});
});

Try with:
$('.show_r3c').click(function() {
$(this).parent('tr').next('tr.r3c').toggle();
return false;
});

perhaps this would work:
$(document).ready(function(){
$(".r3c").hide();
$('.show_r3c').click(function() {
$(this).parent().siblings(":first").toggle();
return false;
});
});

Related

jQuery select not working in Meteor 1.1.0.2 onRendered

I am working on an app I had deployed, and trying to get everything up to the latest version and update the code to take advantage of the latest processes, like subscribing in the Template.onRendered, but I have seemingly broken my sortable.
My template (simplified somewhat)
<template name="formEdit">
<div id="formContainer">
{{#if Template.subscriptionsReady}}
{{#with form this}}
<table id="headerFieldsTable" class="table">
<tbody id="headerFields">
{{#each headerFields}}
<tr class="headerFieldRow">
<td>{{> headerFieldViewRow }}</td>
</tr>
{{/each}}
</tbody>
</table>
<h5>Form Fields</h5>
<table id="formFieldsTable" class="table">
<tbody id="formFields">
{{#each formFields}}
<tr class="formFieldRow">
<td>{{> formFieldViewRow }}</td>
</tr>
{{/each}}
</tbody>
</table>
{{/with}}
{{else}}
Loading...
{{/if}}
</div>
</template>
And the template's onRendered():
Template.formEdit.onRendered(function() {
var formsSubscription = this.subscribe('formById', this.data);
var headerFieldsSubscription = this.subscribe('headerFieldsForForm', this.data);
var formFieldsSubscription = this.subscribe('formFieldsForForm', this.data);
var formEditTemplate = this;
this.autorun(function() {
if (formsSubscription.ready() && headerFieldsSubscription.ready() && formFieldsSubscription.ready()) {
formEditTemplate.$(''));
formEditTemplate.$('#headerFields').sortable({
axis: "y",
stop: function(event, ui) {
var headersToSave = [];
$('#headerFieldsTable div.headerField').each(function(idx, headerFieldDiv) {
var header = Blaze.getData(headerFieldDiv);
header.sequence = idx;
headersToSave.push(header);
});
_.each(headersToSave, function(header) { header.save(); });
}
});
formEditTemplate.$('#formFields').sortable({
axis: "y",
stop: function(event, ui) {
var feildsToSave = [];
$('#formFieldsTable div.formField').each(function(idx, formFieldDiv) {
var field = Blaze.getData(formFieldDiv);
field.sequence = idx;
feildsToSave.push(field);
});
_.each(feildsToSave, function(field) { field.save(); });
}
});
}
});
});
But for both the headers and footers, the formEditTemplate.$('#headerFields') and formEditTemplate.$('#formFields') both seem to return no results. It seems like the DOM is not actually present. I thought the .ready() call on all the subscriptions would correct that, but think there is a timing issue where Blaze hasn't fixed up the DOM yet, but the subscriptions are indeed done. I say this because I put a breakpoint in Chrome right at the first line of the if, and the browser was still showing "Loading...".
I also attempted to hot-wire things by having a helper that setup the sortable placed at the end of the {{#with}} block, hoping that maybe it would be rendered last, but that didn't work either.
I found some articles on the Meteor forums that seemed to suggest adding a timer, but this seems very "hackish". Is there a new pattern for running JS that requires the DOM to be fully initialized?
Instead of the time delay hack, I recommend you use Tracker.afterFlush() to guarantee that the DOM has been created and updated. Here is a description from Meteor docs:
Schedules a function to be called during the next flush, or later in
the current flush if one is in progress, after all invalidated
computations have been rerun. The function will be run once and not on
subsequent flushes unless afterFlush is called again.
So inside of your if statement, you can wrap the code block like so
if (formsSubscription.ready() && headerFieldsSubscription.ready() && formFieldsSubscription.ready()) {
Tracker.afterFlush( function () {
//Code block to be executed after subscriptions ready AND DOM updated
});
}
Here is a reference with examples using Tracker.afterFlush.

Meteor - Strange behavior when using {{#if}} to setup table rows

I'm trying to setup a table using alternating row colors. I'm having trouble getting Meteor to let me use the #if statement to start each row.
Here is the simple helper to determine if the row number is odd or even;
Template.drillDown.trx = function() {
return trx.find({userID: Meteor.userId()});
}
Template.drillDown.isEven = function(num) {
return !( num & 1 );
}
and I have this in the template named drillDown;
<table>
{{#each trx}}
{{#if isEven trx_num}}
<tr class="even">
{{else}}
<tr class="odd">
{{/if}}
<td>{{trx_num}}</td>
</tr>
{{/each}}
</table>
I get the error unexpected {{else}}. I've tried setting this up other ways where I pass in the entire tag like <tr class="even"> but then it throws an error when it see's the closing tag. Any suggestions on how to get past this problem?
The issue is that you are wrapping just the start tag in the {{#if}} block. In Spacebars, everything has to be a complete element with a start and end tag.
The best way to accomplish what you're looking for is:
Helper:
Template.drillDown.isEven = function() {
return !( this.trx_num & 1 );
}
HTML:
<tr class="{{#if isEven}}even{{else}}odd{{/if}}">
<td>{{trx_num}}</td>
</tr>
Also, you could avoid this whole matter entirely and use tr:nth-child(even) instead of even and odd classes: http://www.w3.org/Style/Examples/007/evenodd.en.html
I would change if helper like this:
Template.drillDown.isEven = function() {
return !( this.trx_num & 1 );
}
(I assume helper returns correct answer)
Then, if statement can look like this, cause I guess this line causes trouble
{{#if isEven}}
Also, if you have more helpers, better way to manage them is to keep them this way
Template.<template>.helpers({
isEven: function() {
return !( this.trx_num & 1 );
},
trx: function() {
return trx.find({userID: Meteor.userId()});
},
})

Text flashes and disappear

This question will be similar to this one I asked earlier. I got it working, copied solution, but there must be something Im missing here. I start with the code:
router.js:
this.route('note',{
path: '/note/:_id',
data: function() { return Notes.findOne(this.params._id); },
});
this.route('notes', {
waitOn: function() { return Meteor.subscribe('notes')}
});
template 'notes' :
<table id="notes-table">
{{#each notes}}
<tr id="table-row">
<td id="indicator"></td>
<td id="remove-note" class="icon-close notes-table-class"></td>
<td id="notes-title" class="Nbody notes-table-class">{{this.title}}</td>
<td id="notes-body-prev" class="Nbody notes-table-class">{{this.body}}</td>
</tr>
{{/each}}
</table>
helpers.js :
Template.notes.events({
'click .Nbody': function(events,template){
console.log('displaying note : ' + this._id);
Router.go('/note/'+this._id);
}
});
Template 'note' is simple {{title}} and {{body}}
The problem is, when I click on the note table body it does take me where it should be, which is single note, but its text just flashes for a second and disappear immediately and never comes back, so I see nothing..
Question: What is the problem?
I do not get any error in the console.
The Differences between this and 'memo' solutions are:
- here im using table instead of span's
- I dropped wrapping clickable body in 's tags ( I think this might be the reason )
You have to subscribe in 'note' route to be able to retrieve it:
client:
this.route('note',{
path: '/note/:_id',
waitOn: function() { return Meteor.subscribe('note',this.params._id )}
data: function() { return Notes.findOne(this.params._id); },
});
this.route('notes', {
waitOn: function() { return Meteor.subscribe('notes')}
});
server:
Meteor.publish('note', function(noteId){
return Notes.find(this.params._id);
})
In comment you wrote that it started to work when you : moved waitOn to Router.configure. Route.configure waitOn is working for all routes and because Method.publish('notes') function probably returns Notes.find() then note starts to work correct.

How to tell meteor to "watch" for changes in an array?

I have something like this:
<template name ="products">
<br />
<h2>Products</h2>
<table>
<tr>
<td>Name</td>
<td>Price</td>
</tr>
{{#each products.items}}
<tr>
<td>{{name}}</td>
<td>{{price}}</td>
</tr>
{{/each}}
<tr>
<td>Total:</td><td>{{products.totalPrice}}</td>
</tr>
</table>
</template>
Template.products.helpers({
products: function () {
try {
var user = Session.get("user");
return JSON.parse(localStorage[user]); //this return*
} catch (e) {
}
}
});
*this returns something like this {totalPrice: 30, items:[{"productId1","name1","10"},{"productId2","name2","20"}]}
The question is: I need to have this info stored in localStorage and not in a Meteor.Collection as i dont want to go to the server until moment X (Doesn't matter really). But I cant make this thing auto update whenever I change localStorage value. Is there any way to do this?
Thanks in advance.
That's what Dependencies are for. Simplest example:
var array = [];
var arrayDep = new Deps.Dependency();
Template.name.helper = function() {
arrayDep.depend();
return array;
};
var change = function() {
// do things to Array contents
arrayDep.changed();
};
Store the info in the Session as it is reactive so your template will change every time the value in the Session changes.
You could also use the browser-store package that seems to make localstorage reactive.

Cannot select grid element through jQuery

This is a follow-up question to ASP.NET How to pass container value as javascript argument
Darin Dimitrov has kindly provided his answer using jQuery,
But for some reason, I was not able to select the grid row I wanted to.
Here is the jQuery used to select row.
$(function() {
$('#_TrustGrid input[name^=trustDocIDTextBox]').each(function(index) {
$(this).click(function() {
alert('Hello world = ' + index);
setGridInEditMode(index);
});
});
});
Here is the actual output HTML markup.
<input
id="_TrustGrid_ctl16_ctl05_ctl00_trustDocIDTextBox"
type="text" value="198327493"
name="_TrustGrid$ctl16$ctl05$ctl00$trustDocIDTextBox"/>
I have just started using jQuery tonight and been going through the official jQuery Selectors documentation but have been unsuccessful.
Am I missing something here?
What I did to save the full id of the control I used in my .aspx page:
<input type="hidden"
id="SubcontractorDropDownID"
value="<%= SubcontractorDropDown.ClientID %>" />
You can then just get the value of the id and then use that in your query to know which row to use.
At first glance, I think you just want a '$' instead of '^' and you should be targeting the ID and not the NAME in your selector?
$(function() {
$('#_TrustGrid input[id$=trustDocIDTextBox]').each(function(index) {
$(this).click(function() {
alert('Hello world = ' + index);
setGridInEditMode(index);
});
});
});
I do not know why selecting through #_TrustGrid would not work.
I was able to get around the problem by specifying :input as shown below.
$(function() {
//$('#_TrustGrid input[id$=trustDocIDTextBox]').each(function(index) {
$(':input[id$=trustDocIDTextBox]').each(function(index) {
$(this).click(function() {
alert('Hello world = ' + index);
setGridInEditMode(index);
});
});
});

Resources