I want to make it so that everytime you click on an 'h2' tag, the 'input' inside gets selected and the 'h2' tag changes background, but if another 'h2' tag is clicked, the current highlight and 'input' selection changes accordingly.
problem is that I have 3 different that do the same and with my code all the 3 forms are affected rather one. How do i limit my changes to only be contained to that form. Here is some code for clarification
'
<form>
...
<h2 onclick="document.getElementById(1001).checked='True'
$('h2').removeClass('selected');
$(this).addClass('selected');
">
CONTENT
<input type="radio" name="radio" id="1001" value="1001" />
</h2>
...
</form>
I think this is what you need:
$("form h2").click(function() {
var form = $(this).closest("form");
$("#"+$(this).text().trim()).prop('checked', true);
form.find('h2').removeClass('selected');
$(this).addClass('selected');
});
All the changes are confined to elements within this form.
#Barmar has answered this from a code perspective. Let's see about helping pass some knowledge on. There are some non-code concepts that will help you avoid this problem in the future.
This is a common, and very frustrating, mistake with understanding how JavaScript and HTML work together. The JavaScript doesn't full "belong" to the h2 element when you put it in the onclick attribute, it just runs when you click it. The JavaScript can touch anything in the rest of the page. That's why $('h2').removeClass() is selecting every h2 element.
In general, you should do a few things to help your confusion.
Put your JavaScript in script blocks, or better yet separate
files, not inside HTML elements.
Use jQuery to only deal with the
one h2 at a time (as Barmar suggested).
Do some reading how how jQuery selectors work. jquery.com documentation is very good, it will be time well spent.
Related
I was hoping someone could help me out with this simple question: I’ve just started to learn jQuery and found a code to show hidden text after selecting an item.
I’d like to update it so that:
a.) The selected item is bold
b.) I can add placeholder text instead of starting off with a blank hidden text field
I foolishly assumed I could solve a.) by using the :active property in css, but that only works as long as the link is clicked on. (As soon as you release the mouse button it’s gone.) Just like b.), this is probably only possible by using jQuery as well? If so, would be really great if you could show me how to solve it. :)
The codes: http://jsfiddle.net/KUtY5/1/
JS
$(document).ready(function(){
$("#nav a").click(function(){
var id = $(this).attr('id');
id = id.split('_');
$("#menu_container div").hide();
$("#menu_container #menu_"+id[1]).show();
});
});
CSS
#menu_container {
width: 650px;
height: auto;
padding-left: 30px;
}
#menu_container div {
display:none;
}
HTML
<div id='nav'>
<a id="show_apps">Appetizers</a> | <a id="show_soups">Soups and Salads</a> | <a id="show_entrees">Entrees</a>
</div>
<div id="menu_container">
<div id="menu_apps">
Content of the App Section Here
</div>
<div id="menu_soups">
Content of the Soups Section Here
</div>
<div id="menu_entrees">
Content of the Entrees Section Here
</div>
</div>
Updated fiddle
You can realize a) using a custom class bold for example and the following code :
CSS
.bold{ font-weight: bold;}
JS
$(this).addClass('bold').siblings('a').removeClass('bold');
For b) I can't find any textfield in your code.
Hope this helps.
I have added some extra lines to your code and you can check it from here http://jsfiddle.net/KUtY5/483/.
You bold like this
$("#nav a").css("font-weight", 400); // First you make them thin
$(this).css("font-weight", 800); // Than you make them bold
You put placeholder like this
<div id="placeholder">
Placeholder
</div>
$("#placeholder").hide();
On the other hand I recommend you not to hide menu container. Rather hide the elements inside the menu_container. So you can put a plcaeholder in menu container and you can hide it.
To figure this out 2 questions must be asked / solved
how do you normally make text bold on a page... css right?
where do you want those styles to be defined? There are 2 places:
a. You can define it inside the javascript.
b. You can define it inside the projects css through normal methods (inline, external, embedded).
What's the difference? If you define it inside the javascript the code is self-contained. What i mean by that is you can copy/paste the JS code from one project to the next and you don't need to worry about copying related styles from the stylesheets or other sources because it's all in the JQuery that you've written.
In contrast if you define it outside the javascript in the regular places the code may not be self-contained however some find it easier to manage in the scope of that particular project because all your css is contained in one place (external stylesheet typically).
If you want to take option a, see the .css() method
If you want to take option b, see the style manipulation (toggle class in particular)
Note the examples in the above references should get you 90% of the way to understanding it.
Some final words. Learn Jquery, but i advise you to stay away from it as much as possible because it implements DOM thrashing instead of DOM caching (sizzle engine).
This video series will briefly go into why Jquery sucks for performance in the first video and the rest of the series is about how to create modular vanilla JS.
JQuery goes back and searches the DOM every time you need to make a change that is what
$.(*element*) is doing instead of just caching it.
The more nodes you have in the DOM the more processing power is used searching (because it has to go through the entire tree).
Then on top of that the more elements you have to make changes to (say if you use a css class selector) you have to add even more processing on top of that.
All this is fine if you're on a desktop, but what about a mobile platform? Where would you get all this processing power from?... It doesn't exist.
This may have been answered elsewhere but I couldn't find a question which fit my circumstances.
I have a site page which out puts in DIVs records from a database, this the same DIV looped. In this DIV I have a button which brings up a modal box. This modal DIV however is not coded within the looped DIV.
I need the modal box to be able to get the ID of the record for the data which the looped DIV is showing.
The button is:
<a href = "javascript:void(0)"onclick = "document.getElementById('light2').style.display='block';document.getElementById('fade').style.display='block'">
<div class= "obutton feature2">Reserve Book</div>
</a>
I assume I'll need to use java script somehow, but I don't know how to use it in this manner.
Ideally using some sort of form $_POST would be easiest with the form button having the set value of the $row->ID, but I can't make a form button also a can I?
Sorry for the possibly silly question, as I've said I've found similar things asked, but always find it hard to understand the full workings on other peoples scenarios as opposed to my own.
All help appreciated -Tom
I think the key to your answer is understanding how JS (and jQuery) uses this. When a function is called, the caller is almost always passed as the this variable. For example:
<button data-id="1234" onclick="runThisFunction()" value="run" />
<script>
function runThisFunction() {
//Do Stuff
var data_id = this.data('id');
};
</script>
In the above code, this contains the button that was clicked on. You can get lots of information from the this variable. In jQuery, you can even get to siblings, parents, or children in the DOM.
Here is an example solution to your question:
http://jsfiddle.net/yr6ds/1/
Here is a more elegant solution:
http://jsfiddle.net/yr6ds/2/
The code below works fine with ONE Reveal/Hide Text process
<div class="reveal">Click Here to READ MORE...</div>
<div style="display:none;">
<div class="collapse" style="display:none;">Collapse Text</div>
However if this code is duplicated multiple times, the Collapse Text shows up and doesn't disappear and in fact conflicts with the Expand to reveal even more text instead of collapsing as it should.
In this http://jsfiddle.net/syEM3/4/ click on any of the Click Here to READ MORE...
Notice how the Collapse Text shows up at the bottom of the paragraphs and doesn't disappear. Click on the Collapse and it reveal more text.
How do I prevent this and getting to work as it should?
The two slideDown function calls are not specific to the .reveal and/or .collapse that you are currently doing. i.e.
$(".collapse").slideDown(100);
will find all the elements with the class .collapse on the page, and slide them down. irrespective of what element you just clicked.
I would change the slideDown call to be relavant to the element you just clicked i.e. something like this
$('.reveal').click(function() {
$(this).slideUp(100);
$(this).next().slideToggle();
$(this).next().next(".collapse").slideToggle(100);
});
in your code
$('.reveal').click(function() {
$(this).slideUp(100);
$(this).next().slideToggle();
$(".collapse").slideDown(100);
});
$('.collapse').click(function() {
$(this).slideUp(100);
$(this).prev().slideToggle();
$(".reveal").slideDown(100);
});
this two rows doesn’t do what you want as they act on all elements of the specified class
$(".reveal").slideDown(100);
$(".collapse").slideDown(100);
When you do $(".collapse").slideDown(100);, jQuery runs slideDown on everything with the .collapse class, not just the one that's related to your current this. To fix this, refer to the collapse based on its location to $(this).
Do do this, use something like $(this).siblings(".collapse").slideDown(100);
Note that this particular selector will only work if you enclose each text block in its own div. With each text element in its own div, like you have it now, .siblings(".collapse"), which selects all the siblings of $(this) with the collapse class, will still select both of the collapse elements.
Okay, I think you should take a different approach to your problem.
See, jQuery basically has two purposes:
Selecting one or more DOM elements from your HTML page
manipulate the selected elements in some way
This can be repeated multiple times, since jQuery functions are chainable (this means you can call function after function after function...).
If I understood your problem correctly, you are trying to build a list of blog posts and only display teasers of them.
After the user clicks the "read more" button, the complete article gets expanded.
Keep in mind: jQuery selects your elements very much like CSS would do. This makes it extremely easy to
come up with a query for certain elements, but you need to structure your HTML in a good way, like
you would do for formatting reasons.
So I suggest you should use this basic markup for each of your articles (heads up, HTML5 at work!):
<article class="article">
<section class="teaser">
Hey, I am a incredible teaser text! I just introduce you to the article.
</section>
<section class="full">
I am the articles body text. You should not see me initially.
</section>
</article>
You can replace the article and section elements with div elements if you like to.
And here is the CSS for this markup:
/* In case you want to display multiple articles underneath, separate them a bit */
.article{
margin-bottom: 50px;
}
/* we want the teaser to stand out a bit, so we format it bold */
.teaser{
font-weight: bold;
}
/* The article body should be a bit separated from the teaser */
.full{
padding-top: 10px;
}
/* This class is used to hide elements */
.hidden{
display: none;
}
The way we created the markup and CSS allows us to put multiple articles underneath.
Okay, you may have noticed: I completely omitted any "read more" or "collapse" buttons. This is done by intention.
If somebody visits the blog site with javascript disabled (maybe a search engine, or a old mobile which doesn't support JS or whatever),
the logic would be broken. Also, many text-snippets like "read more" and "collapse" are not relevant if they don't actually do anything and are not part of the article.
Initially, no article body is hidden, since we didn't apply the hidden css class anywhere. If we would
have embedded it in the HTML and someone really has no JavaScript, he would be unable to read anything.
Adding some jQuery magic
At the bottom of the page, we are embedding the jQuery library from the google CDN.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
This is a best practice and will normally speed up your page loading time. Since MANY websites are embedding
jQuery through this URL, chances are high that its already in the visitors browser cache and doesn't have
to be downloaded another time.
Notice that the http: at the beginning of the URL is omitted. This causes browsers to use the pages current protocol,
may it be http or https. If you would try and embed the jQuery lib via http protocol on a https website, some browsers will refuse to download the file from a unsecure connection.
After you included jQuery into the page, we are going to add our logic into a script tag. Normally we would
save the logic into a separate file (again caching and what not all), but this time a script block will do fine.
Finally some JavaScript
At first, we want to hide all elements with the css-class full, since only teasers should remain displayed. This is very easy with jQuery:
$('.full').hide();
The beginning of the script $('.full') tells jQuery: I need all elements with the CSS-class full. Then we call a function on that result, namingly hide() which purpose should be clear.
Okay, in the next step, we want to add some "read more" buttons, next to every teaser. Thats an easy task, too:
$('.teaser').after('<button class="more">Read more</button>');
We now select every element with the css-class teaser and append some HTML code after() each element - a button with the css-class more.
In the next step, we tell jQuery to observe clicks on every one of this freshly created buttons. When a user has clicked, we want to expand the next element with the css-class full after the clicked button.
$('.more').on('click', function(){
//"this" is a reference to the button element!
$(this).slideUp().next('.full').slideDown();
});
Phew, what did we do here?
First, we told jQuery that we wanted to manipulate this, which is a reference to the clicked button. Then we told
jQuery to hide that button (since its not needed anymore) slowly with slideUp().
We immediately continued telling jQuery what to do: Now take the next() element (with the css-class full) and make it visible by sliding it down with slideDown().
Thats the power of jQuerys chaining!
Hiding again
But wait, you wanted to be able to collapse the articles again! So we need a "collapse" button, too and
some more JavaScript:
$('.full').append('<button class="collapse">Collapse text</button>');
Note: we didn't use the after() function to add this button, but the append() function to place the button
INSIDE every element with the css-class full, rather than next to it. This is because we want the
collapse buttons to be hidden with the full texts, too.
Now we need to have some action when the user clicks one of those buttons, too:
$('.collapse').on('click', function(){
$(this).parent().slideUp().prev('.more').slideDown();
});
Now, this was easy: We start with the button element, move the focus to its parent() (which is the element that contains the full text) and tell jQuery to hide that element by sliding it up with slideUp().
Then we move the focus from the full-text container to its previous element with the css-class more, which is its expanding button that has been hidden when expanding the text. We slowly show that button again by calling slideDown().
Thats it :)
I've uploaded my example on jsBin.
So the old JavaScript aficionado and the young jQuery wizard in me are having a little disagreement. Sorry for the long setup, but the heart of the issue is whether to embed onClick code directly in my HTML or to go jQuery-style and and use bind() or click(). I find myself & myself disagreeing on this topic quite often, so I thought I would try generate some discussion on the issue. To explain the issue, the pattern below seems to bring this to the forefront most often.
Typical Example
I'm writing a search for a member directory. On my interface I have various filter criteria like "gender", "member since", and "has profile photo". A criteria looks like this ...
A user can select an option by clicking on the text (e.g. "Female") or choosing the radio button.
When a selection is made the appropriate radio button is selected the text is bold-ed
My html ends up looking something like ...
<div id="FilterContainer_GenderDIV">
<span id="FilterLabel_Gender">Gender:</span>
<span id="FilterSelection_Gender">Any</span>
<span id="FilterChicklet_Gender" class="sprite_MediumArrowDown inline" ></span>
<div id="FilterOptions_GenderDIV">
<input type="radio" id="GenderID" name="GenderID" value="1"/> <a href="" id="FilterOptionLink_CoupleGender_1" >Male</a><br />
<input type="radio" id="GenderID" name="GenderID" value="2"/> <a href="" id="FilterOptionLink_CoupleGender_2" >Female</a><br />
<input type="radio" id="GenderID" name="GenderID" value="0" checked="checked"/> <a href="" id="FilterOptionLink_CoupleGender_0" class="SearchSelectedChoice" >Any</a><br />
</div>
The issue really arises when a user clicks on the text link. At that point I need to know which radio set to change,which link text to bold, and take the newly selected text and change my header label. I see a few options for making this type of scenario work.
Options for making it work
jQuery Injection with Clever element names
I can use jQuery to bind to my elements in a generic fashion. $('#FinderBodyDIV input:radio').click(SearchOption_Click); Then sort out the appropriate ID & text with clever dom inspection. For example, name my hyperlink could be named GenderID_Link_1 where 1 is the ID I should select and GenderID tells me which radio set to change. I could use a combination of '.parents().find()and.siblings()` to find the radio next door and set it with the ID.
This is good because my binding code is simple and my jQuery is separated from my HTML
It's bad because my code functioning now really depends on a brittle HTML structure & naming.
Bind elements individually with eventData
An alternate option is to gather up my set of elements and for each individual element do a 'bind()' passing eventData.
var elements = $('#FinderBodyDIV input:radio');
elements.each ( FunctionWithLogicToBindPassingEventData );
This is satisfying because I've separate the logic for binding event data from a brittle HTML structure.
It's bad because I've simply moved the brittle piece to a new function
It's also bad because I've introduced slowed down (relatively) the binding (more DOM traversal).
Embed onClick code in the HTML
This is where my old JavaScript inclinations keep taking me. Instead of using jQuery to inject bindings, I change my link/radio button HTML to include click handlers. Something like ...
<input type="radio" id="GenderID" name="GenderID" value="1" onClick="SetGender(1,'Male')"/> Male<br />
This is satisfying because i know the values when I'm generating the HTML, so I've simplified my life.
I've removed a lot of dependency on my HTML structure (although not all).
On the down side, I've co-mingled my JS and HTML.
It feels dirty.
So what's a boy to do?
This seems like a fairly common scenario. I find it pops up in quite a few situations besides the one I've described above. I've searched tubes on the interweb, blogumentation, and technical articles on twitter. Yet, I don't see anyone talking about this issue. Maybe I just don't know how to phrase the issue. Whatever the reason, I don't feel good about any of the solutions I've come up with.
It really comes down to how do I associate a clicked element with it's related data--JSON, embedded in HTML names, or otherwise. So what's your take?
The pat answer is that embedding the onClick call in the input element goes against the unobtrusive javascript concept. However, I'm the kind of developer that'll go ahead and use it anyway if it gets the jorb done and the audience is not likely to have javascript disabled.
If I'm understanding the problem correctly, you need a way to do things jQuery-style without relying on html structure and such. Give your radio buttons a class name, for example, the "Male" radio button can have class="Male", and you can select it via jQuery easier.
Bonus: There are some instances where you may need to assign some element more than one class, for example, you are filtering by language and by country. So you can assign some element multiple classes like this:
$('#someElement').addClass('French').addClass('fr-FR');
And select it using either class later.
I'm trying to create a couple of buttons above a textarea to insert some HTML code -- a VERY poor-man's HTML editor. I have a couple of INPUT elements, and I'm using jQuery to set a click handler that will call's jQuery's append() or html() or text() functions.
The handler fires, it shows a debug alert(), but the text I'm trying to append doesn't show up in the textarea. When I inspect the textarea in Firebug, I see the text I'm appending as a child of the textarea -- but it's dimmed, as when an element's style is set to display:none. But Firebug's CSS inspector doesn't show any change to the display or visibility properties.
When I set the click handler to 'append()', and then click multiple times, in Firebug I see the text being added over and over again -- but each new chunk is still invisible. If I choose 'Edit HTML' in Firebug and then type some chars next to the appended text, the entire text block -- the text added by jQuery and the stuff I added in Firebug -- suddenly appear.
This also happens if I don't use a click handler, but call my append function using an inline handler like onclick="javascript:insert('bold');"
Anyone have any idea why the appended text is not displayed?
Here's the relevant code:
The HTML:
<input type='button' id='bold' value='B' onclick='javascript:insert("bold")' />
<textarea name='PersonalGreeting' id='PersonalGreeting'>default text</textarea>
The Javascript:
function insert( cmd ) {
switch ( cmd ) {
case 'bold':
$('#PersonalGreeting').append('<b>bold text here</b>');
break;
}
}
I would guess that jQuery is trying to append HTML DOM elements to the textarea.
Try using the val method to get and set the textarea's value, like this:
$('#PersonalGreeting').val($('#PersonalGreeting').val() + '<b>bold text here</b>');
The basic problem is that you can't put HTML inside a <textarea>. In fact, you can't append HTML elements to one at all. You could use the .val() method to change the text shown inside, but that won't make it bold. That will just make it have <b> showing as part of the text.
An off-the-shelf WYSIWYG editor like TinyMCE is free and easy to implement. Rather than reinvent the wheel (which is a lot harder than it might look), try an existing wheel out.
SLaks and VoteyDisciple are correct. You're usage of append is faulty as you are perceiving it as a string function.
From http://docs.jquery.com/Manipulation/append
Append content to the inside of every
matched element. This operation is the
best way to insert elements inside, at
the end, of all matched elements. It
is similar to doing an appendChild to
all the specified elements, adding
them into the document.
Reinventing the wheel on this one is likely more headache than its worth unless this is an attempt to create a superior, competing product or for your own experimentation.
Also, I would shy away from use of obtrusive JavaScript as you have shown in your example with onclick='javascript:insert("bold")' embedded in the input element. Instead, you'll have a more elegant solution with something like the following:
HTML
<input type="button" value="B" class="editor-command" >
<input type="button" value="I" class="editor-command" >
<input type="button" value="U" class="editor-command" >
JavaScript (not tested)
$(document).ready(function() {
var textarea = $('#PersonalGreeting')
$(".editor-command").each(function(i, node) {
textarea.val(textarea.val() + '<$>text here</$>'.replace(/\$/g, node.value);
});
});
If the main issue is the textarea not being visible, I would try this:
$('#PersonalGreeting').append('<b>bold text here</b>').show();
Might be worth a shot.
edit: In the vain of not trying to reinvent the wheel, I've had success with WYMEditor
You could do this:
$('#PersonalGreeting').append('[b]bold text here[/b]');
But that won't actually render the text as bold. To be honest I'm not actually sure how to render text as bold inside a textarea, I imainge some js trickery.