I have a .mouseover() event triggered on all elements of class 'node'. It works fine, and is also triggered when user hovers over any child of .node. This works well for me, however, I do not want this event triggered if the user mouse overs a specific child, namely, an image.
Why is the selector $('.node :not(img)') not working?
Oddly enough, it does work when I try it out at http://www.woods.iki.fi/interactive-jquery-tester.html, but not in my actual implementation.
My html:
<div id="container">
<div class="node" id="abc">
<h2>Node Title</h2>
<div class="nodeChildren">
<h3 id="a1">Some text</h3>
<h3 id="a2">Some text</h3>
<h3 id="a3">Some text</h3>
</div>
<img src="diagonal-left.gif" />
</div>
</div>
My jquery:
//start with third tier not visible
$('.nodeChildren').hide();
$('.node :not(img)').mouseover(function(){
$(this).children('div').show();
});
$('.node').mouseout(function() {
$('.nodeChildren').hide();
});
});
My failed attempts
$('.node :not(img)') //no mouseover is triggered
//for the following selectors, the mouseover event is still triggered on img
$('.node').not('img')
$('.node').not($('.node').children('img'))
Thanks for any help :)
The problem is the event is "bubbling" up to the parents which triggers the mouse over. You need to add a mouseover to the img to stop this.
$(".node img").bind("mouseover", function(event) {
event.stopPropagation();
});
in the callback function of bind, you can check the target. in your case, Something like this
$(".node").bind('mouseover',function(e){
if(e.target.nodeName != 'IMG'){
$(this).children('div').show();
}
});
Related
I have an event handler that sets a session variable to change the content within a DOM element -- in this case a table cell.
'dblclick td.itemName': function (evt) {
Session.set("editItemName",true);
evt.currentTarget.children[0].focus();
},
<td class="itemName">
{{#unless editItemName}}
{{name}}
{{else}}
<input class="editItemName" type="text" value="{{name}}" style="width:100px;">
{{/unless}}
</td>
Pretty straight forward...
However evt.currentTarget.children doesnt work. Once the input takes place of the text, I'd like to make it automatically focus... The meteor docs say that this is a DOM object so its weird that the children function doesnt work...
Thanks
Chet
When you double click, and your function runs, you set the session editItemName to true, and then you're trying to give the input-element focus, but the template has not been re-rendered yet, so the input-element hasn't been created (the template will be re-rendered some time after your function returns). In other words: evt.currentTarget.children[0] is not a reference to the input-element.
Possible solution 1
In HTML 5 there's an attribute called autofocus, which you can use (at least I can in Chrome). Just add it to the input-element:
<input autofocus="autofocus" class="editItemName" type="text" value="{{name}}" style="width:100px;">
Possible solution 2
Otherwise you have to focus it with JavaScript when the template been rendered and your input-element exists in it:
Template.yourTemplate.rendered = function(){
var input = this.find('.editItemName')
if(input){
input.focus()
}
}
You are trying to set the focus to a DOM element that has not been rendered yet.
The issue has been bothering me for a while. I have tried to use the autofocus='autofocus' HTML attribute: it has no effect in Firefox, and in Chrome, it seems to only work the first time the element is rendered.
So we need a handler that is called just after the template is rendered, in order to set the focus with javascript. Template.templateName.rendered looks like the way to go, but there is an issue:
What didn't work for me:
<template name="itemName">
<td class="itemName">
{{#unless editItemName}}
{{name}}
{{else}}
<input type="text" value="{{name}}">
{{/unless}}
</td>
</template>
Template.itemName.rendered = function()
{
this.$('input').focus()
}
When doing this, Template.yourTemplate.rendered seems to fire only the first time you click on the item (you get the focus correctly only once).
What worked for me:
<template name="itemName">
<td class="itemName">
{{#unless editItemName}}
{{name}}
{{else}}
{{> itemNameEdit}}
{{/unless}}
</td>
</template>
<template name="itemNameEdit">
<input type="text" value="{{name}}">
</template>
Template.itemNameEdit.rendered = function()
{
this.$('input').focus()
}
Any explanation from a Meteor expert?
As #Chet pointed out, Template.[name].rendered no longer fires whenever a template is updated, but instead, only when the template is first rendered, and only once.
One can pass a callback to Tracker.afterFlush which will fire every time the template is updated.
i.e. all reactive updates are processed
Template.myTemplate.events({
'dblclick td.itemName': function(e, t) {
Session.set("editItemName",true);
Tracker.afterFlush(function() {
this.find('input').focus();
}.bind(t));
}
});
in ember's official guide, they say it's possible to delete a record using a view, but they don't provide an example of how to do it. i can't understand how views can get the id of the object do destroy.
maybe i didn't understand what's the view purpose? i think it's an event handler (but i see sometimes it's used to render chunks of hbl... maybe that's why i'm confusing)
is there an example of the whole process of deletion anywhere?
thank you
Generally, what you want to do is create an {{action}} in your view that sends an event to where it should actually be handled: either the controller or the route. (In my case, a little of both)
Note: Generally, you don't need to write a View class for templates, unless the view needs a particular event handler. Ember generates a generic view on-the-fly. You can see this through {{log view}}:
<script type="text/x-handlebars" data-template-name="app">
{{log view}}
</script>
If you look in the console you will find that the template app is associated with a view class:
For example, in the following view template, I'm defining a "Delete" button, which will trigger the action remove in the controller.
<script type="text/x-handlebars" data-template-name="product/remove">
<fieldset>
<legend>Remove</legend>
<div class="row-fluid">
Are you sure you want to delete <strong>{{content.name}}</strong>?
</div>
</fieldset>
<ht />
{{#linkTo products class="btn"}}Back to List{{/linkTo}}
<button {{action remove target="controller"}} class="btn btn-danger">
Delete
</button>
</script>
The controller simply gets the content property and signals the route to fire the confirmRemove event, passing its content as the argument
App.ProductRemoveController = Em.ObjectController.extend({
remove: function() {
this.get('target').send('confirmRemove', this.get('content'));
}
});
And the route actually handles it like this:
App.ProductRemoveRoute = Em.Route.extend(App.NotifyHandler, {
setupController: function(controller, model) {
var c = this.controllerFor('product');
controller.set('content', c.get('content'));
},
events: {
confirmRemove: function(record) {
record.deleteRecord();
// should commit here
// this.get('store').commit();
this.controllerFor('application').set(
'notification', 'Product has been removed'
);
this.transitionTo('products');
}
}
});
(see fiddle)
If you want to handle the event directly in the Route, without talking to the controller, in your view template, you simply omit the target="controller", and the framework will look up for a handler of that event in the controller, and if doesn't find, it will look up in the route. In this approach, you have to pass the event argument via Handlebars, if any argument is required. In this case, I know that this represents the content in that template:
<script type="text/x-handlebars" data-template-name="product/remove">
<fieldset>
<legend>Remove</legend>
<div class="row-fluid">
Are you sure you want to delete <strong>{{content.name}}</strong>?
</div>
</fieldset>
<ht />
{{#linkTo products class="btn"}}Back to List{{/linkTo}}
<button {{action confirmRemove this}} class="btn btn-danger">
Delete
</button>
</script>
With this approach, you don't need to define anything in your controller as it will fire the event directly in the route:
App.ProductRemoveController = Em.ObjectController.extend();
(see fiddle)
Update: In order to have the event handled in the object controller, the itemController property has to specify a controller, which should extend Em.ObjectController:
Depot.TransportDocumentsController = Ember.ArrayController.extend
itemController: 'transportDocument'
Depot.TransportDocumentController = Ember.ObjectController.extend
removeItem: ->
alert("aoooo")
The only thing that would be changed in a template would be the mention of the itemController in the {{each}} helper:
{{#each doc in controller itemController="transportDocument"}}
{{doc.number}}
<!-- rest of the template removed to make this short. -->
<button {{action removeItem}} class='btn btn-danger btn-small'>
<i class="icon-white icon-remove"></i>
</button>
{{/each}}
In the action, you don't need to say where the handler is located, as the framework can find the target on its own.
(see fiddle)
I have HTML similar to this :
<div class="MainForm">
<form name="FromName">
<button name="Button1"></button>
...
...
</form>
<Div class="blackBox" style="visibility:hidden;"></div>
<Div class="SubFotm" style="visibility:hidden;"></div>
</div>
Now I can properly find the trigger for my button click in my script, but I'm not able to target only the closet blackbox to turn it visible.
Currently I'm doing :
if (PButtonName=="Fermer") {
$(this).closest("div .ProfileForm").remove(); // Closing Profile Form
} else if (PButtonName=="plusAdresse") {
alert('In');
$(this).closest("div .BlackBox").css("visibility","visible");
}
I can get the alert "In" to show, but not the BlackBox
If I change the
$(this).closest("div .BlackBox").css("visibility","visible");
for :
$("div .FormBlackBox").css("visibility","visible");
It will show, but will also show all the black box in the document.
If you are using the above HTML, or something similar, I would do it using a reference to the parents.
instead of:
$(".MainForm").closest("div .BlackBox").css('visibility','visible');
use
$(this).parents('.MainForm').children('.BlackBox').css('visibility','visible');
This is assuming you have more than one MainForm div and they all have a single child with the BlackBox class.
here is an example.
Instead of what you have done just add styles display:none; to your divs and then show them whenever you want.So you can do this as below:
<div class="MainForm">
<form name="FromName">
<button name="Button1"></button>
...
...
</form>
<div class="blackBox" style="display:none;"></div>
<div class="SubFotm" style="display:none;"></div>
</div>
and then in your script
if (PButtonName=="Fermer")
{
$(".MainForm").closest("div .ProfileForm").remove(); // Closing Profile Form
}
else if (PButtonName=="plusAdresse")
{
alert('In');
$(".MainForm").closest("div .BlackBox").show();
}
And I will recommend you using Switch case instead of loops at this place.
Given a series of a form's Label and Input elements like:
<div class="labelEditwrap">
<div class="editor-label">
<label for="Address">Address</label>
</div>
<div class="editor-field">
<input class="text-box single-line" id="Address" name="Address" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Address"></span>
</div>
</div>
I'm trying to select the outer most div when the textbox gets focus so I can highlight both label and input:
$("input").focus(function () {
$(this).parent().parent().addClass("curFocus")
});
I've tried a few combinations including:
$(this).parent().parent() // seems the most obvious
$(this).parent().parents("div:first")
Another question here asking about .parent().parent() was solved by finding a syntax error unrelated to the selector. However, in this case, I can see my hightlighter class if I go up only one parent level (only highlights the editor's div) and also if I climb 3 levels (highlights the container holding the full form).
thx
OK....its not the selector. All the suggested alternates (and the original) are correctly 'selecting' the outside wrapper div. The problem was the CSS and how Floats are being applied to the Label and Editor divs. This CSS will produce correct highlighting and also let the label/editor fields align themselves correctly. [whew]
Up to you guys the best way to close/edit/retitle the question in hopes of helping other avoid my 4 hour toubleshooting ordeal.
-highly appreciate the time taken-
Possible Solutions:-
$('.text-box').live('focus', function(){
$(this).parent().parent().css('border', '1px solid red');
});
$('.text-box').live('blur', function(){
$(this).parent().parent().css('border', 'none');
});
or
$('.text-box').bind('focus', function(){
$(this).parent().parent().css('border', '1px solid red');
});
$('.text-box').bind('blur', function(){
$(this).parent().parent().css('border', 'none');
});
The solution you suggested should work correctly
$(this).parent().parent();
I think the issue here is that your event is being bound before there is an object to bind it to. Have you bound your function on document ready?
Something like:
$(function(){
$("input").focus(function () {
$(this).parent().parent().addClass("curFocus")
});
});
Otherwise using 'live' or 'on' to bind the event will work dynamically.
so like:
$('input').live('focus', function(){
$(this).parent().parent().addClass("curFocus");
});
Ive been using the following to change the width of the div.my-div that appears after the one you've clicked:
$(".my-div").click(function () {
$(this).next().css({'width':'500px'});
});
As my divs were neighboring, this worked fine:
<div class="my-div">stuff</div>
<div class="my-div">stuff</div>
<div class="my-div">stuff</div>
However now the structure has changed so they are no longer neighboring:
<div>
<div class="my-div">stuff</div>
</div>
<div>
<div>
<div class="my-div">stuff</div>
</div>
</div>
<div class="my-div">stuff</div>
Whats the simplest way to select the next element of the same class?
Thanks
jQuery will return elements in order of their appearance in the DOM.
As such, you could cache all the .my-div elements, use the index()[docs] method to get the index of the one that received the event, increment it and use the eq()[docs] method to get the next one.
var divs = $(".my-div"); // cache all of them
divs.click(function () {
var idx = divs.index( this ); // get the index in the set of the current one
divs.eq( idx + 1 ).css({'width':'500px'}); // get the one at the next index
});
This saves you from doing a bunch of unnecessary DOM selection and traversing.
Example: http://jsfiddle.net/VrATm/1/
EDIT: Posted wrong example link. Fixed.
You can traverse the tree hierarchy. That is, you can first jump to parent, then to next, then to children, like this:
$(this).parent().next().find(' > div').css({'width':'500px'});