I've read through a few posts here regarding this topic, but none seem to answer which method is the best for allowing sub-pages access to the host page's <script> section.
I load home.php, which has a menu displayed in one of its two <div> sections. The HTML for this menu is on home.php itself. The user is able to interact with buttons and dropdowns in the menu portion of home.php through scripts on home.php, like:
$("#graphsButton").click(function() {
if($(this).text()=="Graphs") {
$(this).html("<span><i class='fa fa-check-circle checked'></i> Graphs</span>");
graph = true;
} else {
$(this).html("<span>Graphs</span>");
graph = false;
}
});
After the user performs their initial operations, that larger menu is replaced by a smaller menu to provide the user more screen real-estate, using the following code:
function shrinkMenu() {
$('#search').html('');
$('#search').animate({
width: '4%'
}, 500);
$('#returnMain').animate({
width: '96%'
}, 500);
$('#search').load('smallMenu.php');
}
If the user wants the big menu back, on smallMenu.php I then have another <script> section with this code:
$('#growMenu').click(function () {
$('#search').html('');
$('#search').animate({
width: '20%'
}, 500);
$('#returnMain').animate({
width: '80%'
}, 500);
$('#search').load('largeMenu.php');
});
largeMenu.php contains a duplicate copy of the original HTML for the menu that loaded along with home.php, and visually, it looks exactly the same to the user.
As I toggle between large menu and small menu however, the <script> sections contained in home.php that pertain to the id tags in the original menu HTML that loaded with home.php no longer work.
In order to make it work, it seems that I would have to re-initialize all my plugins on each page load, and maintain 3 separate pages' <script> sections that are all duplicates of one another, and this seems very inefficient and probably not the best way to go about this.
Is there a better way for me to achieve the functionality I am trying to code here?
Update
My code looks like this at a high level:
<div class="searchParent" id="search">
<div class="return"></div>
<div class="menu">
<div class="largeMenu" id="largeMenu"></div>
</div>
</div>
What you are doing is fine by replacing the menu from a php file that contains a "partial view" which is your menu HTML. The partial view relies upon the parent page code, so you don't need to duplicate any code from the parent script into the partial view. The partial view can expect there is script code on the parent page it can be used with.
As I toggle between large menu and small menu however, the
sections contained in home.php that pertain to the id tags in the
original menu HTML that loaded with home.php no longer work.
The problem you are having though is that you need to ensure that the code on home.php that references these menus uses a parent container as its reference point instead of direct IDs. You are replacing elements (menus), so the bindings are lost when you do that unless you bind on a parent higher up the DOM that doesn't get replaced (remember that events bubble up).
From what I see in your code snippets, it looks like the menu is loaded into the #search container. So just ensure the code in home.php uses that container as the reference point, using something like on like this:
$('#search').on('click', '#graphsButton', function() {
// ...
});
Related
I have a page with a "left" div, that contains a menu, and a "right" div, which holds a content that changes, loaded using javascript as in:
document.getElementById("content").innerHTML='<object type="text/html" data="templates/login.htm"> </object>';
It works okay the first time I click a link on the left menu. Now, this new loaded content has also some inputs that should do the same thing. Only it seems that they can't see the "content" div as having this id, or something else. How do I accomplish this? (fixed menu on left, and on the right we would have changing content - which would have several inputs as well). Thanks.
ADDENDUM - The contents of the js function is just the line pasted above. Probably the flow will clarify?
Step 1 - load menu on left and initial content on right. No user intervention
Step 2 - click "login" on left menu. Login page (separate html) loaded on right side. All fine.
Step 3 - click "cancel" in newly loaded login menu on right side... nothing happens, despite that button having the exact same onclick that the left side menu had (the one used to load the login scren in step 2)
When tracing through parents of this "cancel" button, the trace never "saw" the div.
This was the output of "parent hunting"
object HTMLParagraphElement (button is in a )
object HTMLTableCellElement
object HTMLTableRowElement
object HTMLTableSectionElement
object HTMLTableElement (so far so good... this should be a table containing the button clicked)
object HTMLBodyElement (mmm shouldn't I have a div here?)
object HTMLhtmlElement
object HTMLDocument
null
(now... shouldn't I have a div between body and table elements?)
Seems the partial html loaded inside the div cannot see it?
If that code-sample is used in your project, the missing > might be the source of your troubles.
document.getElementById("content").innerHTML='<object type="text/html" data="templates/login.htm"></object>';
Okay...
Seems the loaded content can't intrinsically "see" the parent div or its id by default. The solution was to have:
parent.document.getElementById("content").innerHTML='<object type="text/html" data="templates/login.htm"></object>';
instead of
document.getElementById("content").innerHTML='<object type="text/html" data="templates/login.htm"></object>';
Just as a little pre-info, I'm running a Volusion e-commerce site that has internal page HTML locked down, so I am unable to add any ID's or classes to internal page elements.
The default HTML provided by Volusion puts a table out of order for my design on my category pages. I have a bit of script that targets that table on my product category pages, and moves it. The problem is that the script is run after the page is loaded, causing a "jumping" effect as the table is moved via jquery.
The simple solution would be to hide the table first via css, and then have the jquery show the element after it has been moved, however, I am unaware of how to accomplish this.
Here is the moving script. It first detects if the user is on a category page via a URL check. It then finds the first child table inside the #content_area element, and moves it.
<script type='text/javascript'>
$(function () {
if (location.pathname.indexOf("-s/") != -1) {
var table_to_move = $("#content_area").find("table").first();
$("#content_area").find("form").before(table_to_move).show();
$('#jmenuhide').insertBefore('.refinement_price_section');
}
else {
}
});
</script>
I have tried targeting the element via css, and hiding it, and then re-showing it after the script has run. However, since I can only reference it through css selectors, and not an ID or class, the page will end up hiding the wrong table, as the table orders change when the script is run.
Anyone have any idea how I can smooth out this table movement? Thanks!
You can view this script in action at: http://www.yandasmusic.com/Folk-Instruments-s/1821.htm
I'm working on a project and I am attempting to create a modal dialog "pop-up" to capture data in a form. I haven't worked with jQuery UI's Dialog widget previously, but I've worked with others and it seemed straight forward.
I created the following very simple code snippet to test as I went along:
<div class="app-email">
<div>
<a href="#"
class="app-email-opener">
Click to add or edit your e-mail settings.
</a>
</div>
<div class="app-email-modal">
Oh, Hai.
</div>
</div>
$('.content').on({
click: function () {
console.log('I was totes clicked.');
var parent = $(this).parents('.app-email');
console.log(parent);
var target = parent.find('.app-email-modal');
console.log(target);
$(target).dialog('open');
}
}, '.app-email-opener');
$('.app-email-modal').dialog({
autoOpen: false,
modal: true,
show: false
});
For reference: the class 'content' is a higher level block to catch delegated events without having to go all the way up the DOM.
The issue I'm running into is that the div with class="app-email-modal" seems to flash onto the page and then disappear from the DOM completely. jQuery, therefore, isn't able to find it and do anything because at that point it simply doesn't exist.
The overall project is in ASP.NET MVC 4, using Visual Studio 2013.
Any information would be greatly appreciated.
So, finally discovered what's happening via this previously answered question:
Jquery Dialog - div disappears after initialization
//EDIT
For any possible future usefuless -
What was happening was that jQuery UI will move any DOM elements specified as Dialogs to the bottom of the page, rather than keep them in the location specified in the HTML markup. So, in my case, I was looking for things by class, but only within the scope of the app-email-openers parent app-email div.
To remedy this, I used templating (in my case, Razor) to add unique ids to each app-email-modal div, and added a data- attribute to associate the link with the specific unique id. This way they jQuery UI can move the elements as it sees fit, but there still easily accessible.
//END EDIT
I feel like that functionality should be better spelled out in the documentation. Even their own example doesn't operate like this.
Corollary: I attempted to use the appendTo option to have the DOM elements not be shifted to the bottom of the page, but they're still moved to the bottom. So, there's that.
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.
I've got a website and I'd like to make a part of it static. What happens is that the header, the menu bar and the footer are consistent in every page. I'd like to have them always loaded and when I click the menu button, it will only reload what is the body of the site.
Is there a simple chunck of code that can early achieve this? Something in js or ajax? I'm sorry but I don't have enough experience in these languages to accomplish something on my own. I've already tried to check jQuery library but it's still pretty confusing to me.
Thank you.
I think you don't even need Ajax or css!! Just use iFrames!! They are awesome, what happens is that u only design one page as the holder of your static content (Header-Menu ...) and put one iFrame in there as a place holder for any page you want to load in it, u should use proper css code to place the iFrame where you want, now, for every link in your menu, just set the "target" attribute equal to your iFrame's name and all the links will be loaded in that iFrame and your page won't be reloaded with every link click... I'll be back with some code...
Just add in every page a div container with ID for header, menubar and footer and just load it with this:
$(document).ready(function(){
$('#header').load('header.html');
$('#menubar').load('menubar.html');
$('#footer').load('footer.html');
});
Just make sure that the html files don't have html, head or body tags within, only the HTML-Code you would write inside the div. It's just like the include function in PHP.
EDIT:
For easy and simple implementation store the code above inside a .js file (e.g. include.js) and add this inside every head just below the include of all other scripts of your html files:
<script type="text/javascript" src="include.js"></script>
EDIT2:
Another solution ist to load the content of the page instead of the header, menubar, footer.
Here you take the same specifications (no html, body, etc. tags inside your content html files)
Name your content div e.g. <div id="content"></div>
Your navbar for example:
<div id="navbar">
Content1
Content2
</div>
JavaScript Code:
$(document).ready(function() {
//Click on a link that's child of the navbar
$('#navbar > a').click(function() {
//Get the html file (e.g. content1.html)
var file = $(this).attr('href');
//Load this file into the #content
$('#content').load(file);
return false;
});
});
You should consider the use of Server Side Included : http://httpd.apache.org/docs/current/howto/ssi.html
It's not quite easy to understand (as it refer to apache configuration), but this is a really great solution.
In a nutshell, you include parts of html code in you main page :
<!--#include virtual="/footer.html" -->
You won't have to use or understand all JQuery Framewol, user agent won't have to parse (if they are able to !) Javascript.
This is a pretty good replacement of PHP / ASP / Java for this kind of purpose.
You could use ajax to request the body of each page. But this is only one possibility - there are many. An other approach could be to create you page content using a script language (php, perl) serverside and employ a function there which adds footer, header and anything else to each page.
If you have an idea of Jquery then use click event on menu links to load the page in a div like the following syntax may help you.
$(document).ready(function(){
$("a.menu").click(function(){
$("#bodyContent").load("http://abc.com/your-linked-page.html");
});
});
To load the url dynamically use the following code:
In your menu bar the link looks like:
Home
In your Jquery code:
$(document).ready(function(){
$("a.menu").click(function(){
url = $(this).attr("title"); // here url is just a variable
$("#bodyContent").load(url);
});
});
Step 1: Add Jquery file into your html page.
Step 2: Use the above jquery code and change your menu link to the new what i said here.
Step 3: If you done it correctly, It will work for you.
How about a traditional iframe?
In your menu:
<a target="body" href="URL_to_your_Menu1_page">Menu1</a>
and then further in the document:
<iframe name="body" src="URL_to_homepage"></iframe>
You may use frameset and frames and organize you pages accordingly. So, frames containing menus can always be at display and while displaying contents on click of menu u may set target to frame in which you would like to load the contents.