How do I detect if a javascript constructor already been run? - javascript

I'm using the jquery-tools tabs and carousel in a page I'm working on. The carousel is embedded within a tab, and the tab is loaded in a beforeClick callback.
Normally, the carousel is initialized in the document ready function like so:
$(function() {
// initialize scrollable
$("div.scrollable").scrollable({
size: 3,
clickable: true,
loop: false
}).mousewheel();
This doesn't work when the carousel is loaded via beforeClick, because it when the DOM is ready, this tab hasn't been loaded yet.
$("ul.tabs").tabs("div.panes > div", {
initialIndex: 0,
onBeforeClick: function(event, i) {
// get the pane to be opened
var pane = this.getPanes().eq(i);
var src = this.getTabs().eq(i).attr("href");
var langPattern = "/^" + getLang() + '/';
var forceReload = false;
if (src.match(langPattern) == null)
{
src = getLang() + "/" + src;
forceReload = true;
}
if (pane.is(":empty") || forceReload) {
// load it with a page specified in the tab's href attribute
pane.load(src);
// initialize scrollable - ONLY SHOULD BE DONE ONCE
$("div.scrollable").scrollable({
size: 3,
clickable: true,
loop: false
}).mousewheel();
}
}
}).history();;
My question is a two-parter:
First, is there an event I can add a handler to to initialize the scrollable when it is first loaded?
Second, if there isn't, is there a way I can find out if the scrollable has been constructed yet?
The idea behind this code is to load localized html fragments based on the user's language selection. This is for a catalog on a CD, not online.

You might want to check out the jQuery live event. This event matches all current and future DOM matches.
EDIT 1
You want to bind to div.scrollable's onload event, correct?
$('div.scrollable').live('load', function() {
// etc.
});

I solved my problem by attaching a callback to the load call:
pane.load(src, "", function(){
$("div.scrollable").scrollable({
size: 3,
clickable: true,
loop: false
}).mousewheel();
});

Related

Call user defined jQuery function with JS

I use a jQuery window libray https://github.com/humaan/Modaal
which triggers events this way $("class of element").modaal({arg1, arg2,...});
--- I updated my question here to make it more general and used an iframe / Html instead of an external svg ---
To trigger an element e.g. in an external Html which is loaded within an iframe, I applied the following code to the iframe:
<iframe src="External.html" id="mainContent" onload="access()"></iframe>
which calls this function:
function access() {
var html = document.getElementById("mainContent").contentDocument.getElementById("IDofDIVelement");
html.addEventListener('click', function() {clicker();});
}
function clicker()
{
// console.log('hooray!');
$("#mainContent").contents().find("IDofDIVelement").modaal({});
//return false;
}
Actually it will only work on every second click. Any idea what I did not consider properly?
Best
You do not need to wait windows loading but iframe only:
$(function() {
$("#mainContent").bind("load",function(){
var myIframeElement = $(this).contents().find(".modaal");
myIframeElement.modaal({
content_source: '#iframe-content',
type: 'inline',
});
});
});
The reason why it did not work was that the iframe was not completely loaded, while jQuery tried to attach the function. As $(document).ready(function(){} did not work, the workaround was to initialize it with
$( window ).on( "load",function() {
$("#mainContent").contents().find("IDofDIVelement").modaal({});
});
This worked properly to attach the functionallity to an element within the iframe.
Actually modaal will vanish the envent handler after the overlay was opened and closed again.
So maybe someone wants to trigger an iframe element for modaal, too, here is a setup which would solve this issue.
(It can be optimised by #SvenLiivaks answer):
$(window).on("load", function() {
reload();
});
function reload() {
var length = $("#iframeID").contents().find("#IDofDIVelement").length;
// The following check will return 1, as the iframe exists.
if (length == 0) {
setTimeout(function() { reload() }, 500);
} else {
$("#iframeID").contents().find("#IDofDIVelement").modaal({
content_source: '#modalwrapper',
overlay_close: true,
after_close: function reattach() {
reload();
}
});
}
}

$ionicposition only setting correct values on a modal the first time a modal is opened

I have created a custom select directive and within this directive when you tap into the options it should use $ionicposition to locate the selected option based on the HTML element ID, and then scroll to it using $ionicscroll delegate.
This is the function which locates the option, and then scrolls to it:
private scrollToOption(selectedCode: activeh.objects.ICode): void {
this.$timeout(() => {
let item: HTMLElement = document.getElementById("code-" + selectedCode.CodeID);
if(item){
var itemPosition = this.$ionicPosition.offset(angular.element(item));
this.$ionicScrollDelegate.$getByHandle('modalContent').scrollTo(0, itemPosition.top + 40, false);
}
}, 200);
}
This is where the scrollTo function is called:
private createModal(): void {
this.$ionicModal.fromTemplateUrl('app/shared/directives/selectoption/selectoption.modal.html', {
scope: this.$scope,
hardwareBackButtonClose: false
}).then((modal) => {
this.selectModal = modal;
this.selectModal.show();
if (this.selectedVal !== undefined) {
this.scrollToOption(this.selectedVal);
}
});
}
So like mentioned in the title, this code works perfectly but only the first time that the modal is opened. After the modal has been closed and opened again the $ionicposition.offset is returning values of only 0.
I found a (probably partial) solution to this, wherein instead of using .hide() to hide the modal I use .remove() to completely remove it forcing a complete rebuild.
This mimics the behaviour where it worked the first time as now every time the modal is opened is the 'first' time.

Select2 Event for creating a new tag

I'm using the jQuery Select2 (v4) plugin for a tag selector.
I want to listen for when a new tag is created in the select element and fire an ajax request to store the new tag. I discovered there is the createTag event but this seems to fire every time a letter is entered into the select2 element. As shown in my fiddle: http://jsfiddle.net/3qkgagwk/1/
Is there a similar event that only fires when the new tag has finished being entered? I.e. it's enclosed by a grey box enclosing it.
I can't find any native method unfortunately. But if you're interested in simple "workarounds", maybe this get you closer:
$('.select2').select2({
tags: true,
tokenSeparators: [",", " "],
createTag: function (tag) {
return {
id: tag.term,
text: tag.term,
// add indicator:
isNew : true
};
}
}).on("select2:select", function(e) {
if(e.params.data.isNew){
// append the new option element prenamently:
$(this).find('[value="'+e.params.data.id+'"]').replaceWith('<option selected value="'+e.params.data.id+'">'+e.params.data.text+'</option>');
// store the new tag:
$.ajax({
// ...
});
}
});
DEMO
[EDIT]
(Small update: see #Alex comment below)
The above will work only if the tag is added with mouse. For tags added by hitting space or comma, use change event.
Then you can filter option with data-select2-tag="true" attribute (new added tag):
$('.select2').select2({
tags: true,
tokenSeparators: [",", " "]
}).on("change", function(e) {
var isNew = $(this).find('[data-select2-tag="true"]');
if(isNew.length && $.inArray(isNew.val(), $(this).val()) !== -1){
isNew.replaceWith('<option selected value="'+isNew.val()+'">'+isNew.val()+'</option>');
$.ajax({
// ... store tag ...
});
}
});
DEMO 2
The only event listener that worked for me when creating a new tag was:
.on("select2:close", function() {
(my code)
})
This was triggered for new tags and selecting from the list. change, select2:select, select2:selecting and any others did not work.
One more simple check will be this based on the difference in the args of the event .....
While I was dealing with this situation, I had seen this difference; that when the new element is created the event args data does not have an element object but it exists when selecting an already available option...
.on('select2:selecting', function (e) {
if (typeof e.params.args.data.element == 'undefined') {
// do a further check if the item created id is not empty..
if( e.params.args.data.id != "" ){
// code to be executed after new tag creation
}
}
})
Another workaround. Just insert it to the beginning:
}).on('select2:selecting', function (evt) {
var stringOriginal = (function (value) {
// creation of new tag
if (!_.isString(value)) {
return value.html();
}
// picking existing
return value;
})(evt.params.args.data.text);
........
It relies on underscore.js for checking if it's string or not. You can replace _.isString method with whatever you like.
It uses the fact that when new term is created it's always an object.

why is my element not targeted when reload through AJAX

I'm using object literals on my project. I'm targeting selecting with jquery. It works fine the first time but when the part I'm targeting is reloaded with AJAX I can't target those element anymore. But I look into firebug they're there...
I'm even doing console.log() to test if my code works and it works but it just doesn't want to pick those. So in order for it to work, I have to refresh the entire browser.
Do you know what's the deal with AJAX dom reload and selectors.
I think it's something to do with the DOM reloading and redrawing itself or something along those lines...
Here is my code:
Module.editWishlistTitle = {
wishListContent: $('.mod-wish-list-content'),
title: $('.title').find('h2'),
titleTextField: $('#wishlist-title-field'),
titleInnerContainer: $('.title-inner'),
editTitleForm: $('.edit-title-form'),
submitCancelContainer: $('.submit-cancel'),
notIE9: $.browser.msie && $.browser.version < 9,
edit: function () {
var fieldTxt = this.titleTextField.val(),
editForm = this.editTitleForm,
titleParent = this.titleInnerContainer,
fieldCurrentTitle = this.title.text();
this.titleTextField.val(fieldCurrentTitle);
this.submitCancelContainer.removeClass('hidden');
if (!this.notIE9) {
editForm.css('opacity', 0).animate({ opacity: 1 }).removeClass('hidden');
titleParent.addClass('hidden').animate({ opacity: 0 });
console.log(editForm);
} else {
editForm.removeClass('hidden');
titleParent.addClass('hidden');
}
}
init: function () {
var self = this;
console.log(this.editTitleForm);
//edit
this.wishListContent.delegate('.edit-title a', 'click', function (e) {
self.edit();
e.preventDefault();
});
};
If you are replacing an element on the page, you are destroying the original reference to the element. You need to redo the reference to point to the new element.
Create a new method in your code that (re)initializes the references you need. Instead of adding them in the odject, set them in the method.
Basic idea:
Module.editWishlistTitle = {
wishListContent: $('.mod-wish-list-content'),
title: $('.title').find('h2'),
//titleTextField: $('#wishlist-title-field'),
...
...
initReferences : function(){
this.titleTextField = $('#wishlist-title-field');
},
...
...
init: function () {
this.initReferences();
...
...
And when your Ajax call comes back you just need to call initReferences again.
After DOM ready, if you inject any data / class / id will not be available in DOM, so better you use live or delegate to get your new data access.
http://api.jquery.com/delegate/
Best to use delegate, that will take care your new data loaded after dom ready, that way you can avoid to refresh /reload your page.

How can I use jQuery and Javascript from firefox add-on?

I can't create a new element in the page. I check the page and domain when the page is onload, that's work, but I don't know how can I create a new element in the correct window page.
window.addEventListener("load", function() { myExtension.init(); }, false);
var myExtension = {
init: function() {
var appcontent = document.getElementById("appcontent"); // browser
if(appcontent)
appcontent.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
},
onPageLoad: function(aEvent) {
var unsafeWin = aEvent.target.defaultView;
if (unsafeWin.wrappedJSObject) unsafeWin = unsafeWin.wrappedJSObject;
var locationis = new XPCNativeWrapper(unsafeWin, "location").location;
var hostis = locationis.host;
//alert(hostis);
if(hostis=='domain.com')
{
var pathnameis=locationis.pathname;
if(pathnameis=='/index.php')
{
$("#left .box:eq(0)").after('<div id="organic-tabs" class="box"></div>'); // this code somewhy doesn't working, but if I copy to FireBug it't work.
}
}
}
}
My question is: How can I use Javascript and jQuery from firefox addon when I want to manipulate html in the correct window content? What is need from here
$("#left .box:eq(0)").after('<div id="organic-tabs" class="box"></div>');
for working.
This code has a bunch of issues. For one, appcontent is not the browser, gBrowser is. So it should be:
init: function() {
gBrowser.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
},
Then, using wrappedJSObject is absolutely unnecessary (and also not safe the way you do it).
var wnd = aEvent.target.defaultView;
var locationis = wnd.location;
Finally, you are trying to select an element in the browser document (the document that your script is running in), not in the document loaded into the tab. You need to give jQuery an explicit context to work on:
$("#left .box:eq(0)", wnd.document)
But you shouldn't use jQuery like that, it defines a number of global variables that might conflict with other extensions. Instead you should call jQuery.noConflict() and create an alias for jQuery within myExtension:
var myExtension = {
$: jQuery.noConflict(true),
....
myExtension.$("#left .box:eq(0)", wnd.document)
Here is a template you can use that incorporates your sample code. I also added an additional statement so you could see another use of jQuery. Important points:
You must load jQuery before you can use it. You should myplace the jQuery library file you want to use in Chrome, for example, in the chrome/content directory.
Use window.content.document as the context for every jQuery
operation on the contents of the Web page
Use this as the context of a successful search result to help you
insert code in the correct spot.
window.addEventListener('load', myExtension.init, false);
var myExtension = {
jq : null,
init : function() {
var app;
// Load jQuery
var loader = Components.classes["#mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://myExtension/content/jquery-1.5.2.min.js");
myExtension.jq = jQuery.noConflict();
// Launch extension
if ((app = document.getElementById("appcontent"))) {
app.addEventListener("DOMContentLoaded", myExtension.run, true);
}
},
run : function() {
// make sure this is the correct Web page to change
var href = event.originalTarget.location.href;
if (href && href.match(/http:\/\/(www\.)?domain\.com\/(index\.php)/i)) {
changeScreen();
}
},
changeScreen : function() {
// make changes to the screen
// note the "window.content.document) in the first jQuery selection
myExtension.jq("#left .box:eq(0)", window.content.document).after('');
// note the use of "this" to use the search results as the context
myExtension.jq("#right", window.content.document).each(function() {
myExtension.jq("tr td", this).append('MATCH!');
});
}
}

Categories