I'm trying to build a single-page app that has several views (screens, page contents)
My App's UI has a permanent menu bar and a "view area" which retrieves a view via Ajax, based on menu selections. This works great for simple HTML content and keeps my menu-script running on the background despite which view is being displayed.
But what if my view needs an additional script? How do you load and execute a script as a result of a view change (=a page fragment was loaded as a result of a button click) also, how do I get rid of that script when I choose a different view?
I know I can embed a script-tag into the page fragment and write the code there, but I'm really looking for a more robust way of doing this, preferably so that an instance of an object is created when the view is loaded and then discarded when the view changes.
yepnope.js is a great conditional loader. You could use it to check certain conditions (e.g. view, state) before loading a script. I don't think it has the ability to remove a script that's already been loaded, though.
You can use javascript to add a <script> tag in the same way you would any other tag.
The hardest part is knowing where to place it, but if you have control over your markup, this isn't too big a barrier.
Something along these lines:
function DST(url)
{
var s = document.createElement(’script’);
s.type=’text/javascript’;
s.src= url;
document.getElementsByTagName(’head’)[0].appendChild(s);
}
If you need something to happen automatically when you load that script, you should be able to use a self executing anonymous function to do the job.
(function(){alert('this happened automatically');})();
If you need to pass anything in to the function it would look like this:
(function($){alert('this happened automatically');})(jQuery);
If you really need to discard the scripts, you can delete the nodes, but it might be better to leave them in, in case a user reactivates a view, so you don't have to make the AJAX call and associated HTTP request, allowing the page to load faster.
Related
I am currently trying to implement the Google Tag Manager but I run into a problem since the GTM appends the tags right before the closing tag of the body.
Whenever I have a template that needs to call a bit of code from one of the scripts in the Google Tag Manager I get an undefined error. This is obvious since it does not matter where I place my script in my view, GTM will always come after it since it appends right before the closing body tag.
Is there any way to fix this behaviour and why does Google do it like this? I understand that it helps with non-blocking but they might as well just place async attributes on the scripts and it will almost do the same?
An example I have Facebook Pixel as one of my tags in GTM and I need to be able to make a specific event call when I am loading a certain page as my view.
fbq('track', 'Search');
Ofcourse this needs a fbq instance to begin with. This leave me with only one option and that is to try and place my script in my footer which is a general template and it will get messy.
Any workaround for this behaviour?
The issue you are facing is that the Facebook library is not completely loaded when you are calling your function.
One method would be to migrate your Facebook code to GTM trigger it on all pages
and fire your specific code on dom ready
You could also use the code from below and see when the _fbq.loaded variable is set to true.
https://gist.github.com/chrisjhoughton/1dc91dd7bd95717e08d3
You would have to create trigger based on this javascript variable.
Hope this helps
I am creating an application with Symfony2, where I have a main menu of options depending on the option selected dynamically opens a tab at a lower div with the content for that option. Content is loaded with load() of Jquery in the container div.You can see in the picture below:
The first problem was that in the HTML loaded in each tab could not use the js file initially loaded in the index.html, as you can see in this example you should check out a notice when we click the content of each tab, but does nothing .
The solution to this problem was included in each HTML code to load the appropriate script, and it worked properly. But to do it this way, if two HTML carry the same js, when one of the contents some event runs is repetite many times as tabs we have created, that is, if I open two different options (each in its own tab both charge the same js) by clicking on the first event associated performed twice, whereas if I do it in the second only done once. In short, whenever a function of a js used, is repeated as many times as there are dynamically loaded on the tabs.
And I tried event.preventDefault();orevent.stopPropagation(); and it does not solve the problem.
Would it be okay that it js is included twice in the overall structure of HTML? (Included in the initial head and then the container div)
Dynamically loading HTML + JavaScript is not the best approach for this case. I suggest that you use some JavaScript SPA framework, like AngularJS or ReactJS. Both are very big and well supported projects, so you can find tons of documentation and tutorials. You'll most likely end up using Symfony only as a RESTful service and Angular/React taking care of the rest (template loading, sending request to server, etc). Also, js frameworks will take care of deep linking and in the end you'll have a better working, easier to maintain application.
It is a bit more work initially, especially until you bootstrap the application, but then it gets easier to maintain and implement new functionality, so it pays off in the end. With your current approach you soon will find yourself in a big mess full of 100s of templates, js callbacks, inclusions, etc. I'm saying this from a personal experience!
Well...
Jquery works like this: when you attach an event to html, if the html does not exist, the event is attached to nothing. If the element exists then the event is correctly attached. It attaches only to existing elements when the on function is execute. That is a correct behaviour. In the past it used to exist a .live method that did exactly what you want: you attached an event and if you create the element after the attachment, the new element also contained the event.
Adding the js twice is not the solution. As you said after a click the button will be executed twice.
Why do not attach the events after loading the content? If you load it in the page start you can do in the main file:
$(function(){ // will force to execute the on method after all the page is loaded.
$('.submenu .button').on ('click', function (){
...
});
});
If you load the menu by ajax, in the callback and after adding the html menu to the main you must use the code I wrote above.
I have an application that uses jQuery and pjax (standalone). We're trying to experiment to see if we can use the possibly more flexible and smaller npm pjax over jquery-pjax.
One of my functions sets the html of a div after loading data, and this html includes links that we want as pjax links, for example $('#link-container').html('<a href="/account_detail.html?='+account.id+'" data-pjax >'). However clicking on this link causes a full page reload rather than a pjax request.
Is there a way to reimplement pjax? When I try new PJAX({elements:[a[data-pjax]]}) inside the pjax:success call (whenDOMReady from the project page - https://www.npmjs.org/package/pjax) it uses pjax... but then loads resources twice.
Perhaps the best solution is going with jquery-pjax ($(document).pjax(a[data-pjax] etc.) but I wanted to see if anyone has come across this type of issue before. Perhaps it is rare to include jQuery and non-jQuery pjax, but it seems like this can happen for any asynchronous data query and DOM modification, and I just want to re-PJAX.
I'm using jquery-pjax, and when you use it or configure it wrong - it also refresh the page, so you're experiencing one of the issues I've encountered.
In any way, I'm not sure if it will help your problem or not, but I suggest everyone to use Firefox with Firebug and in the "Console" tab to click on "Persist" you usually find some errors there that might be helpful, and since errors somewhere might cause the page to refresh - sometime you miss it as the console is being refreshed too.
What I learned is that you need to make sure that when you write:
<a href="/account_detail.html?=2" data-pjax>bla</a>
You need to have a container - that PJAX drops the content into, like:
<div id="pjax-container"></div>
And initially you configure PJAX to bind these objects:
<script>
// this is how I define it in jquery-pjax, so adjust it as you use it.
$(document).pjax('a[data-pjax]', '#pjax-container');
</script>
so the key points that I learned that causes refresh with PJAX:
I'm sending a header twice ( back-end code )
The container was suddenly removed from the HTML body ( the div id="pjax-container" ) and when the DOM is missing it doesn't have a
place to drop the HTML - so it just refresh the page.
When I initially bind the a[data-pjax] with jQuery, new DOM object are not automatically re-bind by jQuery ( unless using "live/on"), therefor they act as a regular <a> tag and reload the page with the new URL.
some JS/PJAX syntax error
In your case, if the pjax-container is "#link-container" I'm not sure if it's a good idea to place the tags inside it.
In teaching students in an intro web class, I want to find the most straight-forward way of building a multipage static site of about 7 pages without having them have to make 7 different pages.
Obviously, I can have them make a separate header, footer, and menu file, and use server side includes, and just put the includes onto 7 different pages of content - but that feels dirty.
In the past I had them doing it this way: http://www.tropicalteachers.com/web110/?Ignore_WEB_119_CLEAN:MX_-old_Extra_Credit:Dynamic_PHP - this was a quick experiment using the assignment as a model: http://www.yetirobotics.org/index2.php?pagename=team_yeti
but i feel like there should be a cleaner/simpler way to do it using javascript, or maybe in php - but i'm not sure of how.
Basically i'd like one main page with a menu -and when the menu items are clicked, it loads different content. I believe it's better to have the content in seven different files, but i could imagine it all being in the same JS within one page- remember, this site should be pretty simple.
I'd like to limit it to html/css/js/php, and preferably js OR php and not both.
with just the index page controlling (and loading) everything.
Thanks!
If you want to create a more modern framework then you should look into using javascript for displaying content dynamically (as you suggested in your question). To do this I would make use of a framework like jQuery as it makes asynchronous request calling far more simple. To do this you would code a single page with a specific area marked for the dynamic content.
Server side you would setup either pages or a database to return the main content area that will change upon request.
Client side you can use jQuery's load to place the requested content into the content area.
$('#contentArea').load('url', function() {
//callback area in case there is other stuff you want to do with js
location.hash = 'blah';
});
It would probably make sense to change the page's hashmark so that pages still seem static and are linkable as content changes.
location.hash = 'blah';
In addition you will need to override default link behavior by returning false when they are clicked.
myLink.click = function() {
$('#contentArea').load('url', function() {
//callback area in case there is other stuff you want to do with js
location.hash = 'blah';
});
return false;
}
I think this would be a good lesson for students as it shows the differentiation between client-side, server-side, and how to connect them dynamically via javascript.
I have a site which pulls pages into a dynamic interface. Currently, the main page requires that any javascript the external pages will need be loaded with the main page. Most javascript the external pages have are objects that are built when the page gets pulled in, but first, which causes issues.
It's a little hard for me to explain for some reason so here's a simple walk through of process.
1.Request a page be pulled in
2.Based on a variable passed to function create a specific object which will be associated with the physical html coming from the page ( This is the external Javascript)
3.Load page into the objects frame
This flow requires that the external javascript be attached to the main page not the page being pulled in.
I want to switch steps 2 and 3, but I assume that I will need a way to know that the page and all its scripts have fully loaded before attempting to create the designated object, but I have no idea how to do that.
I am using jQuery and hope that this can be accomplished without a plugin but if it is needed then so be it.
Thanks
Update
Good questions. So the pages are local pages that we build at this point, so we know what to expect. Also the pages are loaded just into basic div structure.
Specifically the main page makes a request to get a page. That page is returned in the form of a string and is then pasted into a div element that is on the main page. The pages are more like fragments I guess. But they can range from fairly complicated and require a bit of javascript to not using any javascript at all.
And the external javascript would generally be added via a script tag and is not inline.
Due to the dynamic nature of the page we do NOT use IFRAME's, they cause issues with the movement of our modules.
If you're using an iframe then I imagine you are changing it's src attribute. To get an alert on when that iframe is done loading you should include a script on the page within the iframe:
<script>
$(window).load(function() {
alert("All Done");
});
</script>
If you are just requesting a string version of a page via AJAX and populating a div you need some extra JavaScript to detect when those dynamically loaded script files have finished downloading to the client.
I would visit this link to get you started.
A combination of Nick and Mic's solution.
In your IFRAME pages, you need a way to determine when the content is done loading, or ready, and then alert your main page:
<script>
$(function() {
parent.frameReady();
});
</script>
In your main page, you can code in the hook from your IFRAMEs:
<script>
function frameReady() {
// attach custom js to iframe here
}
</script>