Dynamically loaded javascript doesn't work second time loaded - javascript

I am working on a webpage that uses a JQuery UI dialog (in modal mode) to display a form that is dynamically generated using Django. The basic flow is:
the user clicks a button
jquery (using AJAX) issues a get request that returns the html for the form which is then used to fill the dialog
The html contains a script tag that handles some UI on the form which loads fine and works as expected
the user than fills out the form and clicks "Done" and the form is submitted.
The issue comes in when the user makes an error on the form. The server responds to the post request (that submits the form) with the original form (including the script) modified to show the errors. This second time the script is loaded it gets a "Uncaught ReferenceError: $ is not defined (anonymous function)" The script is exactly the same as before when it worked fine. To be clear throughout this entire process the page is never refreshed.
Here is the gist of the javascript that takes care of the modal:
var add_container = $("#add_container");
add_container.dialog({...})
function show_form(form,response_func) {
add_container.html(form);
add_container.dialog("open");
$("#add_form").submit(function (event) {
return submit_form($(this),response_func);
});
}
function submit_form(form,response_func) {
add_container.append('<p>Adding...</p>');
//this is a trick to upload a file without reloading the page
form.attr('target','upload_target');
$('#upload_target').load(function() {
var response = $('#upload_target').contents().find('body').html();
add_container.dialog("close");
resp_obj = $(response)
if (resp_obj.is('form')) {
//***this is what reloads the form when there is an error
show_form(response,response_func);
} else {
response_func(resp_obj);
}
});
}
$('#add_link').click(add_link);
function add_link() {
$.get('/add_link', function(data) {
function add_response(response) {
//handle successful submission
}
show_form(data,add_response);
});
}
//...more stuff that is not important
This is the gist of the html returned from /add_link
<script type="text/javascript" src="/scripts/add_form.js" ></script>
<form id="add_form" enctype="multipart/form-data" action="/add_link/" method="post">
<!-- Dynamically generated form here !-->
</form>
The add_form.js is a pretty standard javascript file that uses jQuery. Its starts with $(document).ready(function () {...} ) and the first $ is where the ReferenceError occurs
The form needs to be dynamically generated based on what is clicked so I can't just put everything statically on the page. The script is not dynamically generated so it doesn't necessarily need to be dynamically loaded but I wasn't sure how to keep it in its own file, and also only have it run when the form is loaded. I am open to suggestions of alternative ways to accomplish the same effect.

Your form action is pointing to a different relative path to the one containing the jQuery framework script, etc.
<script type="text/javascript" src="/scripts/add_form.js" ></script>
<!-- src="/scripts" -->
<form id="add_form" enctype="multipart/form-data" action="/add_link/" method="post">
<!-- action="/add_link" -->
To make sure it's loading the framework after the form submission, just use something like the developer tools on your browser and check the head tag for the jQuery script src. Is it still there?

Thanks to MelanciaUK I realized that when I submitted my form to the iFrame the response was getting sent first to there where the script would run and error because the iFrame is treated as its own page and doesn't have access to jQuery loaded on the main page.
I decided to solve the problem by eliminating the dynamic loading of the add_form script and simply load it when the page loads just like all my other scripts. I created a custom jQuery event (using .trigger) in order to only have the script run when the add form is opened. This worked exactly the way I wanted it to.
Hope this helps anyone with a similar problem. If you have any questions feel free to ask!

Related

Ajax submit script global

I have this piece of code. this code has to be inside every new loaded ajax page. cause if its outside, it wont work.
example:
<div> Loaded form here , including the script </div> <- works
<div><div> Loaded form here , </div> script is here </div> <- do not work
Q: How can i make it able to work without the need to put this script on every of my ajax pages?
code:
<script>
$("form").on("submit",function(e) {
e.preventDefault();
var btn= $(this).find("input[type=submit]:focus");
$('<input>').attr({
type: 'hidden',
name: btn.attr('name'),
value: btn.val()
}).appendTo('form');
action = $("form").attr('action');
$.post(action, $(this).serialize(), function(data) {
$(".main_center").html(data);
});
return false; // prevent normal submit
});
</script>
if the script is in the loaded file, it will proccess correctly. but if it isnt, it will just refresh the page. cause the loaded file will not find the script that is ment to be used.
Is your script in the .main_center div?
If so then the returned data will replace it - hence you need to include your script in the data returned in your ajax call.
Putting the script into a common js file included in your footer works (I've done it myself) so the fault is almost certainly with the structure of your document and the way you are replacing content.
Will need to see a more of the actual code to properly advise you.
[Edit] Have you tried
<div class="main_center">
<div><form> ....</form></div>
</div>
<script>
$(document).on("submit","form", function(e){ ... });
</script>
This binds the script to the document and calls it whenever a form is submitted, including forms loaded after the page has been generated

Dynamic Follow Up Page with Marketo Forms

We are using a script that allows us to to change the follow up URLS of a form dynamically so we can use the same form across multiple assets but have different follow up pages.
The issue is that script only works when it loads the form itself rather than bringing it in via the visual editor. If we adjust the code as per the instructions on the developer site to make it work with the visual editor, it stops working.
We need to bring the form in via the editor because we have another script that only works on forms that are loaded in that manner. This script opens the follow up page in the parent window rather than the iframe.
Can you provide any suggestions?
Here's the code for the script:
Dynamic follow up URL:
<script type="text/javascript">// <![CDATA[
MktoForms2.whenReady(function(form){
//Add an onSuccess handler
form.onSuccess(function(values, followUpUrl){
//Take the lead to a different page on successful submit, ignoring the form's configured followUpUrl.
location.href = "http://solutions.healthcaresource.com/2346-staff-assessment-thank-you.html";
//return false to prevent the submission handler continuing with its own processing
return false;
});
});// ]]>
Use document.getElementById('iframe_id').src (given an iframe with an id of 'iframe_id'):
location.href = "http://solutions.healthcaresource.com/2346-staff-assessment-thank-you.html";
To this
document.getElementById('iframe_id').src = "http://solutions.healthcaresource.com/2346-staff-assessment-thank-you.html";
You can add Marketo variable to be able to give dynamic followup link.
Add following meta for variable, and use it in script. Code will be like this in your landing page.
<meta class="mktoString" id="ThankyouPage" mktoName="Follow-up Page" default="Add dynamic followup page here" allowHtml="false">
<script>
MktoForms2.whenReady(function (form) {
form.onSuccess(function(values, followUpUrl) {
location.href = ${ThankyouPage};
return false;
});
});
</script>

Multiple jQuery document.read event handlers running in wrong order

I recently added a feature to our ASP.NET MVC web application. There's a page that is displayed when the user clicks on an item in a table. The page uses AJAX to display a partial view in a single div in the page's HTML. The partial view uses the Telerik Kendo UI to define and display dialogs and DropDownList controls. This is complicated in that the JavaScript imports are all on the View for the page, while the PartialView just builds the HTML to be displayed in the div.
The JavaScript I wrote on the page includes a jQuery document.ready event handler:
$(document).ready(
function () {
if ( $('#details-map').val() != '' )
$('#details-map').remove();
var urlTail = '?t=' + (new Date().getTime());
// Make the AJAX call and load the result into the details box.
$('#detailsbox').load('<%= Url.Action("Details") %>' + '/' + '<%: Model.Id %>' + urlTail, displayDetails);
}
)
This works fine when I run the application on my localhost. The problem appears when I deploy the page to our development server. In this case, there's an additional document.ready event handler that's emitted to very end of the page by the Telerik Kendo / ASP.net MVC extensions:
<script type="text/javascript">
//<![CDATA[
jQuery(document).ready(function(){
if(!jQuery.telerik) jQuery.telerik = {};
jQuery.telerik.cultureInfo=...;
});
//]]>
</script>
On this page, the $(document).ready event handler I wrote runs before the Telerik handler, and my code clearly depends on the Telerik handler running first. When mine runs first, I get a JavaScript error that says "jQuery.telerik.load is not a function'.
Since this does not happen on my localhost, how do I make sure that the second document ready event handler is run first?
Edit:
After more research, I've found that the problem is that the two scripts mentioned in my answer, which are supposed to be written to the page via the following line in the Master Page used by my page:
<%= Html.Telerik().ScriptRegistrar().Globalization(true).jQuery(false).DefaultGroup(group => group.Combined(false).Compress(false)) %>
Are not being loaded. In other words, the above line does nothing. It works on another page that uses the same Master Page, though. I've placed a breakpoint on the line and it is executing. Does anyone have any ideas?
You're either going to have to make it show up after the second one on the page OR do something I hate to suggest:
$(document).ready(function() {
function init {
/* all your code that needs to be run after telerik is loaded */
}
if ( $.telerik ) {
init();
} else {
setTimeout(function check4telerik() {
if ( $.telerik ) {
return init();
}
setTimeout(check4telerik, 0);
}, 0);
}
});
So, if $.telerik is loaded, it runs, otherwise it polls until it's set, and when it is set, it runs the code. It's not pretty, but if you don't have more control, it's probably your only option, unless $.telerik emits some kind of event that you can hook into.
After spending a few hours working on this, I finally got it to work. The problem turned out to be that two JavaScript files that are used by the Telerik DropdownList control and Window control were not being loaded.
In spelunking through the JavaScript on the page, I came across this script that was generated by Telerik:
if(!jQuery.telerik){
jQuery.ajax({
url:"/Scripts/2011.3.1306/telerik.common.min.js",
dataType:"script",
cache:false,
success:function(){
jQuery.telerik.load(["/Scripts/2011.3.1306/jquery-1.6.4.min.js","/Scripts/2011.3.1306/telerik.common.min.js","/Scripts/2011.3.1306/telerik.list.min.js"],function(){ ... });
}});}else{
jQuery.telerik.load(["/Scripts/2011.3.1306/jquery-1.6.4.min.js","/Scripts/2011.3.1306/telerik.common.min.js","/Scripts/2011.3.1306/telerik.list.min.js"],function(){ ... });
}
This script was emitted by a call to Html.Telerik.DropdownListFor() in my partial view. I'm guessing that the code to include for the two JavaScript files mentioned in the code, telerik.common.min.js and telerik.list.min.js, was not emitted since the call was on a partial view. Or I was supposed to include them all along & didn't know it (I'm very new to these controls). Oddly, everything worked when I ran it locally, so I don't get it.
In any case, I added two <script> tags to my View to include these files and everything started working. That is, I added the following tags to my page:
<script type="text/javascript" src="../../Scripts/2011.3.1306/telerik.common.min.js"></script>
<script type="text/javascript" src="../../Scripts/2011.3.1306/telerik.list.min.js"></script>
Live and learn.

How to realize screens / views with JavaScript / Jquery easily?

I'm sure I'm missing something pretty basic, but I have just started to get myself up to speed on jQuery and Javascript programming. Previously I was doing server side programming with PHP.
I'm now in the middle of creating a prototype for HTML5 webapp, where I would like to have different screens. Now with PHP that was pretty easy, I could just used server side templates like Smarty and be done with it.
However to make my app more webapp like, I would like to dynamically change between screens without having to reload the window.
I have looked into several options that might be anwsers to my question, but I'm not sure whether I'm on the right track.
I have checked for example JsRender, JsViews or even the pure jquery load command.
But what I'm not sure is whether these things would allow me to have something like this:
HEADER_PART
MAIN_CONTENT
FOOTER_PART (also contains links to common JS files that I use)
I would like to dynamically update the MAIN_CONTENT part. Currently my application is only one page, and all my custom logic that belongs to that page is in one JS file. In this JS file, I use a simple $(function() { ... to load my page, so whenever it gets loaded, parts of my page get updated asyncronously. This is fine, since all my blocks in this certain page would have to be loaded when that one page gets loaded.
But what if I have a link, like main.html#otherscreen, and when I click that screen, I would like to change my MAIN_CONTENT and also run another page load specific JS that handles blocks on that other screen, not the first page?
I know I could still use probably server side templating and load my pages using AJAX requrests, but again, not sure whether that is the right approach.
Could you please enlighten me? :)
Thanks & best regards,
Bence
Check out jQuery.load(). Using this function you can dynamically load content into a div on the page, which is what I think you want to do. Just find the div on the page you want to load content into and call
$('#mydiv').load(url, data, function(response){
//do something once it's done.
});
Per your comments...
This is actually very easy. .load() should replace the content in the div (I think. If not, just call .empty() first). Of course you could get fancy and add effects, like
function changePages(url) {
$('#mydiv').fadeOut('fast', function() {
$(this).load(url, function(response){
$('#mydiv').fadeIn('fast');
});
});
}
To handle things like the hash in the URL, in your click event you have to make sure you first call e.preventDefault():
$('#mylink').click(function(e){
e.preventDefault(); //e is a jquery event object
var link = $(this);
var hash = link.attr('href'); // get the hashtag if the href is '#something'
changePages(someUrl + hash);
});
For dynamic loading of data into the page without changing your header and footer you should use jQuery's AJAX function. It allows you to post requests to the server and receive data back without reloading the page. A simple example would be something like:
<html>
<head>
<title>Example</title>
<!-- Assuming jQuery is already referenced -->
<script type="text/javascript">
$('span.buttonish').click(function(){
$.ajax({
// The URL can be a file or a PHP script of your choosing
// it can also be pure HTML without the <html> tags as they
// are already in your file
url: 'path/to/the/file/that/return/data',
success: function(receivedData) {
// The received data is the content of the file or the return
// data of the script and you can use it as you would with any data
$('#content').html(receivedData);
}
});
});
</script>
</head>
<body>
<div id="header">
<!-- Something -->
</div>
<div id="content">
<span class="buttonish">Click me to change the text... </span>
</div>
</div id="footer">
<!-- Something -->
</div>
</body>
<html>

simple jquery event handler

having some real problems with jquery at the moment. Basically what I have so far is. The form is submitted once the form is submitted a grey box pop's up with the relevant infomation.
What I need to do though is refresh the whole page then allow the grey box to appear.
I have the following code
$("#ex1Act").submit(function() {
//$('#example1').load('index.php', function()
$("#example1").gbxShow();
return true;
});
the line which is commented out load's the page again after the form is submitted the other code makes the grey box pop-up.
Is their a way to say once the:
$('#example1').load('index.php', function()
has been exucted do this:
$("#example1").gbxShow();
hope this makes sense.
This is not possible.
Once the form is submitted, the Javascript running on the page that submitted the form is completely gone; it cannot affect the page that the form returns.
Instead, you should put server-side code in the form that writes $("#example1").gbxShow(); in a separate <script> block if the form has been submitted.
Why not just submit the form normally (i.e., not using JavaScript) and add a variable to the resulting page signalling the need to display the grey box? Like so:
<?php if(isset($_POST['submit'])): ?>
<script type="text/javascript">
var showGreyBox = true;
</script>
<?php endif; ?>
...
<script type="text/javascript">
$(function(){
if(showGreyBox !== undefined){
// execute code to show the grey box
}
});
</script>
Something like that, maybe?
The problem you have is that the web page is "stateless". This means that you can't do a bit of JavaScript, refresh the page and continue on with your JavaScript. When you refresh the page, you lose your current state and the page starts from scratch.
You will need to re-engineer your design to bear in mind the page lifecycle (i.e. all JavaScript stops permanently on navigation).
One solution may be to use the jQuery AJAX forms plugin, which will submit the form to the server and give you back the result of the submission, which would avoid breaking the page lifecycle. You could then display the box as you wish.
The standard way to do this is to have the server return the gray box contents in the response to the form post.
You could probably do this in jquery by putting the page and the grey box into separate iFrames so that it would be safe from the page refresh

Categories

Resources