OrElse
OrElse

Reputation: 9969

How can i call a function within a js file?

I have a JavaScript file AppForm.js, which I wish to reinitialize after a successful ajax post response.

The file itself contains, among others

(function(namespace, $) {
    "use strict";

    var AppForm = function() {
        // Create reference to this instance
        var o = this;
        // Initialize app when document is ready
        $(document).ready(function() {
            o.initialize();
        });

    };
    var p = AppForm.prototype;

    p.initialize = function() {
        // Init events
        this._enableEvents();

        this._initRadioAndCheckbox();
        this._initFloatingLabels();
        this._initValidation();
    };

    p._enableEvents = function () {
       //blah blah blah
       e.preventDefault();
    };

    p._initRadioAndCheckbox = function () {

    };

    p._initFloatingLabels = function () {

    };

    p._initValidation = function () {

    };

    window.materialadmin.AppForm = new AppForm;
}(this.materialadmin, jQuery)); // pass in (namespace, jQuery):

How can I do that?

$.ajax({
    url: path, type: "POST", cache: "false",
    dataType: "html",
    contentType: "application/json; charset=utf-8",
    traditional: true,
    data: JSON.stringify(postData)
}).success(function (data) {
    $("#products-list").html(data);
    //**PERFORM INIT OF JS FILE**

}).error(function (data) {

});

Thanks to Dan's answer the solution is pretty close but the events are not working since e.preventDefault(); is called.

And here is the full script

(function(namespace, $) {
	"use strict";

	var AppForm = function() {
		// Create reference to this instance
		var o = this;
		// Initialize app when document is ready
		$(document).ready(function() {
			o.initialize();
		});

	};
	var p = AppForm.prototype;

	// =========================================================================
	// INIT
	// =========================================================================

	p.initialize = function() {
		// Init events
		this._enableEvents();
		
		this._initRadioAndCheckbox();
		this._initFloatingLabels();
		this._initValidation();
	};
	
	// =========================================================================
	// EVENTS
	// =========================================================================

	// events
	p._enableEvents = function () {
		var o = this;

		// Link submit function
		$('[data-submit="form"]').on('click', function (e) {
			e.preventDefault();
			var formId = $(e.currentTarget).attr('href');
			$(formId).submit();
		});
		
		// Init textarea autosize
		$('textarea.autosize').on('focus', function () {
			$(this).autosize({append: ''});
		});
	};
	
	// =========================================================================
	// RADIO AND CHECKBOX LISTENERS
	// =========================================================================

	p._initRadioAndCheckbox = function () {
		// Add a span class the styled checkboxes and radio buttons for correct styling
		$('.checkbox-styled input, .radio-styled input').each(function () {
			if ($(this).next('span').length === 0) {
				$(this).after('<span></span>');
			}
		});
	};
	
	// =========================================================================
	// FLOATING LABELS
	// =========================================================================

	p._initFloatingLabels = function () {
		var o = this;

		$('.floating-label .form-control').on('keyup change', function (e) {
			var input = $(e.currentTarget);

			if ($.trim(input.val()) !== '') {
				input.addClass('dirty').removeClass('static');
			} else {
				input.removeClass('dirty').removeClass('static');
			}
		});

		$('.floating-label .form-control').each(function () {
			var input = $(this);

			if ($.trim(input.val()) !== '') {
				input.addClass('static').addClass('dirty');
			}
		});

		$('.form-horizontal .form-control').each(function () {
			$(this).after('<div class="form-control-line"></div>');
		});
	};
	
	// =========================================================================
	// VALIDATION
	// =========================================================================

	p._initValidation = function () {
		if (!$.isFunction($.fn.validate)) {
			return;
		}
		$.validator.setDefaults({
			highlight: function (element) {
				$(element).closest('.form-group').addClass('has-error');
			},
			unhighlight: function (element) {
				$(element).closest('.form-group').removeClass('has-error');
			},
			errorElement: 'span',
			errorClass: 'help-block',
			errorPlacement: function (error, element) {
				if (element.parent('.input-group').length) {
					error.insertAfter(element.parent());
				}
				else if (element.parent('label').length) {
					error.insertAfter(element.parent());
				}
				else {
					error.insertAfter(element);
				}
			}
		});

		$('.form-validate').each(function () {
			var validator = $(this).validate();
			$(this).data('validator', validator);
		});
	};
	
	// =========================================================================
	// DEFINE NAMESPACE
	// =========================================================================

	window.materialadmin.AppForm = new AppForm;
}(this.materialadmin, jQuery)); // pass in (namespace, jQuery):

UPDATE 1 I added window.materialadmin.AppForm.Initilize at the ajax response but the events are not working

UPDATE 2 And here is the code that does not work after the postback.

$(".ProductOnlyForDemonstation, .IncludeInMainPage, .Active")
    .on('click', 'button', function(){
        $('.sweet-overlay').toggle();
        if (jQuery("#FORM").valid()) {
            var id = $(this).attr("data-id");
            $.post("/product/DemoIncludeActive", {
                "Id": id,
                "ProductOnlyForDemonstation": $("#ProductOnlyForDemonstation-" + id).is(':checked'),
                "IncludeInMainPage": $("#IncludeInMainPage-" + id).is(':checked'),
                "Active": $("#Active-" + id).is(':checked'),
            },
            function (data) {

            }).success(function (data) {

            }).error(function () {

            });
        }
    });

Upvotes: 17

Views: 2248

Answers (11)

Murat Yıldız
Murat Yıldız

Reputation: 12040

In order to call a function you should take into account the following points below:

The function should be defined in the same file or one loaded before the attempt to call it.

The function should be in the same or greater scope then the one trying to call it.

So, the following example should work:

You declare function fnc1 in first.js, and then in second you can just have fnc1();

first.js :

function fnc1 (){
    alert('test');
}

second.js :

fnc1();
index.html :

<script type="text/javascript" src="first.js"></script>
<script type="text/javascript" src="second.js"></script>

Upvotes: 1

Wirone
Wirone

Reputation: 3373

Related to UPDATE 2

Try to register your events with delegation:

$(document).on(
    'click',
    '.ProductOnlyForDemonstation button, .IncludeInMainPage button, .Active button',
    function() {
        // Your code
    }
);

I suppose you're loading something and render new page content after response, so previously registered events are not attached to new elements. With delegation you'll get your events working even after elements were added to DOM dynamically (if they match with delegating selector), because events are attached to document and bubbled from your buttons. You can attach event deeper in the DOM than document itself, but to the element containing your dynamic content (in other words: to closest element that will not be overriden after completing request).

PS. You can also add some unique class to all .ProductOnlyForDemonstation button, .IncludeInMainPage button, .Active button and delegate events to that class (shorter definition)

Upvotes: 2

ngasull
ngasull

Reputation: 4216

As you're using jQuery validator, you can use Validator's resetForm method in order to reset your form.

For this purpose, you can expose a reset method like follows:

    p.reset = function () {
        // Reset managed form
        $('.form-validate').data('validator').resetForm();

        // Reset custom stuff
        this._initRadioAndCheckbox();
        this._initFloatingLabels();
    };

Note that in order to reset your form correctly after posting your request, you need to isolate event binding from the init stuff, for instance the following event binding should move from _initFloatingLabels to _enableEvents:

    // Link submit function
    $('[data-submit="form"]').on('click', function (e) {
        e.preventDefault();
        var formId = $(e.currentTarget).attr('href');
        $(formId).submit();
    });

Finally, you just have to call window.materialadmin.AppForm.reset() in your POST request's callback.

Upvotes: 0

Vishal Patel
Vishal Patel

Reputation: 1745

I had experienced same issue like you. After reinitializing events,all events are not working properly.

I have tried lots and finally i have found issue.when i am reinitializing all control, all events are rebind.

so they are not fired properly. so please unbind all events related to your control and then init all control agian and bind all event.


Updated answer

if you are using jQuery 1.7 or onwarads then add following code:

$(".ProductOnlyForDemonstation, .IncludeInMainPage, .Active").off();
$('[data-submit="form"]').off('click');
$('textarea.autosize').off('focus');
$('.floating-label .form-control').off('keyup change');
//-----------------
//**PERFORM INIT OF JS FILE**

before this line. //**PERFORM INIT OF JS FILE**

and you are using jquery below 1.7 then use following code:

$(".ProductOnlyForDemonstation, .IncludeInMainPage, .Active").unbind();
$('[data-submit="form"]').unbind('click');
$('textarea.autosize').unbind('focus');
$('.floating-label .form-control').unbind('keyup change');
//-----------------
//**PERFORM INIT OF JS FILE**

before this line. //**PERFORM INIT OF JS FILE**

for more help related to unbind click here.

for more help related to off click here. i hope this will help.

Upvotes: 1

IgrDi
IgrDi

Reputation: 655

Try make it like this:

(function($) {
    "use strict";

    var materialadmin = {};

    var AppForm = function() {
        //closure
        var self = this;

        (function(){
        //todo: init events
        };)();

        //<your AppForm class's props here...>
    };

    materialadmin.Init = function(){
        //create instance of AppForm calss for materialadmin object
        materialadmin.appForm = new AppForm();
    }

    return materialadmin;
//*}(jQuery)); //  syntax mistake, i'm sorry)).*
})(jQuery);

$(document).ready(function(){
    materialadmin.Init();
});

$.ajax({
  url: path, 
  type: "POST", 
  cache: "false",
  dataType: "html", 
  contentType: "application/json; charset=utf-8",
  traditional: true,
  data: JSON.stringify(postData),
  success: function (data) {
    $("#products-list").html(data);
    
    materialadmin.Init();
  },
  error: function(){
    alert('error')}
});

Upvotes: 0

Dan Prince
Dan Prince

Reputation: 29999

You can wrap your code in a global function.

(function(namespace, $) {
  "use strict";
  window.main = function() {
    var AppForm = function () {
    // ...
    };
  };

  window.main(); // you can initialize it here
)(this.materialadmin, jQuery);

And execute it if the response is successful.

.success(function (data) {
  $("#products-list").html(data);
  //**PERFORM INIT OF JS FILE**
  window.main();
}).error(function (data) {

});

Edit: It looks like you're exposing the initialize method on a global object. You can just call that init method when the AJAX response completes.

.success(function (data) {
  $("#products-list").html(data);
  //**PERFORM INIT OF JS FILE**
  window.materialadmin.AppForm.initialize();
}).error(function (data) {

});

Upvotes: 11

YSJ
YSJ

Reputation: 382

I looked at your edit history and saw you did

p._enableEvents = function () {
    var o = this;

    // Link submit function
    $('[data-submit="form"]').on('click', function (e) {
        e.preventDefault();
        var formId = $(e.currentTarget).attr('href');
        $(formId).submit();
    });

    // Init textarea autosize
    $('textarea.autosize').on('focus', function () {
        $(this).autosize({append: ''});
    });
};

If this is still how you enable your events, I suspect the cause might be you have more than one subscription on form click and textarea focus after reinitializing on your ajax callback. I suggest try only do other init tasks, and exclude event bindings in your callback function.

Upvotes: 0

shivgre
shivgre

Reputation: 1173

It should be simple by printing content of this at top of your ajax url script :

<script src="your-js-to-be-initialized.js"></script>

Your jquery ajax code will remain the same. You just need to print the script on each request so that it is reinitialized and binds to your elements.

$.ajax({
    url: path.php, type: "POST", cache: "false",
    dataType: "html", contentType: "application/json; charset=utf-8",
    traditional: true,
    data: JSON.stringify(postData)
}).success(function (data) {
    $("#products-list").html(data);

    //**PERFORM INIT OF JS FILE** 
    //path.php should echo/print the <script src="your-js-to-be-initialized.js">

}).error(function (data) {

});

Upvotes: 0

Shishir Arora
Shishir Arora

Reputation: 5933

some checks for the events to work after postback

1)using $("#products-list").html(data) will remove all the events attached to child elements of #products-list.

So either a)attach events once on "#products-list" only with event-delegation In jQuery, how to attach events to dynamic html elements? or b)reattach events on every child after using $("#products-list").html(data)

2) dont use .html() because it also removes all jquery data and events on children. update independent children elements instead.

Upvotes: 1

Greg
Greg

Reputation: 836

Maybe two solutions

First solution

Create a file js with your functions who will reload.

<script language="text/javascript">
   function load_js()
   {
      var head= document.getElementsByTagName('head')[0];
      var script= document.createElement('script');
      script.type= 'text/javascript';
      script.src= 'source_file.js';
      head.appendChild(script);
   }
</script>

And in your success :

.success(function (data) {
  $("#products-list").html(data);      
   load_js();
}).error(function (data) {

});

2nd Solution

Like the first solution : Create a file js with your functions who will reload.

Use use getScript instead of document.write - it will even allow for a callback once the file loads.

Description: Load a JavaScript file from the server using a GET HTTP request, then execute it.

So you can try this :

.success(function (data) {
    $.getScript('your-file.js', function() {

}).error(function (data) {

});

or simply :

jQuery.getScript('my-js.js');

You will try, and tell me if that helps.

Upvotes: 0

John Slegers
John Slegers

Reputation: 47101

You could add the line namespace.initialize = p.initialize; at the end of your code :

(function(namespace, $) {
    "use strict";

    /* .......  */

    // =================================================
    // DEFINE NAMESPACE
    // =================================================

    namespace.AppForm = new AppForm;
    namespace.initialize = p.initialize;
}(this.materialadmin, jQuery)); // pass in (namespace, jQuery):

Then, p.initialize becomes available globally as materialadmin.initialize, and you can call it from another file like this :

materialadmin.initialize();

Upvotes: 0

Related Questions