I have HTML structure like this:
<div class="parent">
<div class="child">
<div class="something">...</div>
</div>
<div class="child">
<div class="something-else">...</div>
</div>
<div class="child">
...
</div>
...
</div>
I catch events (like click) on .child elements like this:
$('.parent').on('click', '.child', function() { ... });
However, I would like to get rid of explicit class specification and base on the fact of direct ancestry itself.
I want to write the code which would not require any particular classes for children elements. Closest thing to this is:
$('.parent').on('click', '*', function() { ... });
But obviously such handler will spread on deeper descendants (.something, .something-else etc.), not only on the first level.
Is there a way to acheive what I look for, being it using something instead of * or some other way?
P.S. I don't want to use direct binding - $('.parent').children().click(function() {...}); - as it is slower and will not work in case of children being dynamically added.
The selector sought for is > *:
$('.parent').on('click', '> *', function() { ... });
(The actual solution was suggested by Josh Crozier in the comments, I just reposted it as an answer.)
Related
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)
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'});
I have code that looks like this:
<div class="tag">Order # :</div>
<div class="data">
<input type="text" name="oemTeo[<?=$o;?>]" id="o_oemTeo[<?=$o;?>]" value="<?=$vrow['oemTeo'];?>" />
</div>
I want to select (and apply some css to) the <div class="tag"> element directly BEFORE the <div class="data"> element. How would I define that selector using jQuery. I've tried $(this).prev('div .tag') but it did not work.
Thanks
Based on comments, since this refers to your <input> element, you need to go to the .parent() <div> before going to the previous sibling with .prev(), like this:
$(this).parent().prev("div.tag");
.prev() works only on sibling elements, and the <div> you're after isn't a sibling, but rather a sibling of the parent...so you just need to traverse up to that first.
If this is the div.data element, just remove the space from your selector (or eliminate the selector altogether):
$(this).prev('div.tag');
...or if you need to select from the DOM, you could do this:
$('div.tag + div.data').prev();
have you tried
$('div.data').prev().css('background-color', 'red');
this goes back to figuring out what 'this' is like nick said.
Since 'div' with class 'tag' is a sibling for 'div' with class 'data', you can use 'siblings()' method as :
$(function(){
var previousElement = $('div.data').siblings('div.tag');
console.log(previousElement);
});
fiddle link: http://jsfiddle.net/jAnS8/1/
I have 4 divs with content like below:
<div class="prodNav-Info-Panel">content</div>
<div class="prodNav-Usage-Panel">content</div>
<div class="prodNav-Guarantee-Panel">content</div>
<div class="prodNav-FAQ-Panel">content</div>
And a navigation list like this:
<div id="nav">
<ul id="navigation">
<li><a class="prodNav-Info" ></a></li>
<li><a class="prodNav-Usage" ></a></li>
<li><a class="prodNav-Guarantee"></a></li>
<li><a class="prodNav-FAQ" ></a></li>
</ul>
</div>
When the page is first displayed I show all the content by executing this:
$('div.prodNav-Usage-Panel').fadeIn('slow');
$('div.prodNav-Guarantee-Panel').fadeIn('slow');
$('div.prodNav-FAQ-Panel').fadeIn('slow');
$('div.prodNav-Info-Panel').fadeIn('slow');
Now, when you click the navigation list item it reveals the clicked content and hides the others, like this:
$('.prodNav-Info').click( function() {
$('div.prodNav-Info-Panel').fadeIn('slow');
$('div.prodNav-Usage-Panel').fadeOut('slow');
$('div.prodNav-Guarantee-Panel').fadeOut('slow');
$('div.prodNav-FAQ-Panel').fadeOut('slow');
});
So what I have is 4 separate functions because I do not know which content is currently displayed. I know this is inefficient and can be done with a couple of lines of code. It seems like there is a way of saying: when this is clicked, hide the rest.
Can I do this with something like $(this) and $(not this)?
Thanks,
Erik
In your particular case you maybe able to use the .sibilings() method something like this:
$(this).fadeIn().sibilings().fadeOut()
Otherwise, lets say that you have a set of elements stored somewhere that points to all of your elements:
// contains 5 elements:
var $hiders = $(".prodNavPanel");
// somewhere later:
$hiders.not("#someElement").fadeOut();
$("#someElement").fadeIn();
Also, I would suggest changing the classes for your <div> and <a> to something more like:
<div class="prodNavPanel" id="panel-Info">content</div>
....
<a class="prodNavLink" href="#panel-Info">info</a>
This gives you a few advantages over your HTML. First: the links will have useful hrefs. Second: You can easily select all your <div>/<a> tags. Then you can do this with jQuery:
$(function() {
var $panels = $(".prodNavPanel");
$(".prodNavLink").click(function() {
var m = this.href.match(/(#panel.*)$/);
if (m) {
var panelId = m[1];
$panels.not(panelId).fadeOut();
$(panelId).fadeIn();
return false; // prevents browser from "moving" the page
}
});
});