My application is based on 100's of files. the "logic" determine which will be included in a certain display.
In many of them, I have jquery-ui-widgets (for this question, I will assume that they are all tabs).
Some of them are customized and the others are not.
The customized tabs are set individually in the beginning of the complete output (in the html header).
The others are set globally later.
HTML
<div class="some-element">...
<div class="some-other-element">...
<div class="tabs">...
<div class="tabs">...
<div class="tabs">...
<div class="tabs">...
JavaScript
$(".tabs .some-element").tabs({/*some settings*/});
$(".tabs .some-other-element").tabs({/*some other settings*/});
$(".tabs").tabs(); // no settings
My problem is: and I want the last javavscript call to exclude, the already initialized elements.
How can tell if an object is already set?
As #mhu states, you can check for the data value under the name of the widget. The widget framework also sets up a selector which matches the name of the widget itself. This will allow you to test if an item is a widget with:
if ($(testElement).is(":ui-tabs")) {
// testElement is a ui-tabs widget
}
This is actually backed by the data attribute which can only be used to test a single item. The selector can instead be used as follows:
$(".tabs:ui-tabs").each(function() {
// every ".tabs" which is a widget will get a call.
});
You can check the data (example below is for jQueryUI 1.9+):
if ($(".tabs").data("ui-tabs")) {
// ui tab
}
Related
I am doing a school project that is a Movie lookup app connected to guidebox API. I am using Materialize CSS and trying to organize the information into their tabs system. They are added dynamically so the documentation says to initialize in javascript. It says to use:
$(document).ready(function(){
$('ul.tabs').tabs();
});
However that doesn't work for me I guess since the tabs are not present at Doc Ready thaey are not pushed into the DOM until a submit request. I put just the
$('ul.tabs').tabs();
into a few places in my code and the best result was it working on the first movie returned on each search but for each subsequent return item the tabs break.
I could use some guidance on whether I can plug that in somewhere to make my existing code work.
https://github.com/jasonboru/group_project1_guidebox.git
There are some missing ending tags in your dynamically created dom elements.
Apart this, in this file assets/js/logic.js the following there are the following two lines:
$('.guidebox-search-results').append(movieResult);
$('ul.tabs').tabs();
That menas, whenever you add new tabs element you initialize them.
The mistake I see is: in this way you initialize every tabs not only the new one. And, because you have already initilized the old one I can suggest you to rewrite the previous two lines in this format:
$('.guidebox-search-results').append(movieResult);
$('.guidebox-search-results').find('ul.tabs').tabs();
You can bind on every event, when node inserted in dom and after that, do with it what you want.
$(document).bind('DOMNodeInserted', function(e) {
var element = e.target;
});
I have a JSP page with 6 custom widgets in a TabContainer. The code looks something like this:
<div data-dojo-type="dijit/layout/TabContainer" data-dojo-props="region: 'center', gutters:false">
<div data-dojo-type="dijit/layout/ContentPane" title="<b>Registries</b>">
<div data-dojo-type="my/custom/Widget"></div>
</div>
...(5 more ContentPanes like this)
</div>
When the page loads, each tab loads each widget and it's pretty slow. Most of the time, I only need to access one of those tabs and don't care about the others, so I decided I want to load this content dynamically.
When the href property is specified for a Dojo ContentPane, that content will not be loaded or parsed until that tab is selected. The only problem is, that means I would have to create 6 new .html files that have nothing besides in them. It's like a declarative way to programmatically load widgets... kind of weird.
Is there a way I can simply tell the ContentPane I just want it to dynamically load my custom widget instead of having to create html markup? Currently, I created a Spring controller method that accepts a String with a "widget" property and returns a string that is a div with the data-dojo-type set to the widget name, which is a programmatic way define declarative markup to be loaded programatically... it just keeps getting weirder! So now all of my content panes look like this:
<div data-dojo-type="dijit/layout/ContentPane" title="<b>Registries</b>" data-dojo-props='href:"rest/dynamicWidgetHtml/my.custom.Widget/"'></div>
Where "my.custom.Widget" is a spring controller path variable.
Any way to simplify this and eliminate the need for calling the server to build the div so the widget can be dynamically loaded when the tab is selected?
Would like to know how familiar are you with JavaScript and Dojo widgets.?
I have tried to answer the questions with some assumptions.
1) Assuming that data-dojo-type="my/custom/Widget" is a custom dojo widget i.e dojo widget contained in a javascript file.
2) You are able to attach a function to the onShow event of the ContentPane as shown below.
First is you need to attach a function to the contentPane "onShow" event. say myFirstTabContentPaneShowAction()
and specify a element tag with a unique ID. I have used widget1 as an example below. The onShow event will be fired when you select the tab.
<div dojoType="dijit.layout.ContentPane" onShow="myFirstTabContentPaneShowAction()">
<div id="widget1" ></div>
</div>
The myFirstTabContentPaneShowAction() will be as follows.
function myFirstTabContentPaneShowAction() {
require ( ["dojo/parser", "dojo/dom", "my/custom/Widget"] , function ( parser, dom) {
widgetHandle = parser.instantiate([dom.byId("widget1")], {data-dojo-type: "my.custom.Widget"});
});
Hope it helps.
One often have form with some dynamic parts, that needs to be initialized onload. E.g. datepickers, enhanced selects, section toggling, hiding/showing conditional elements etc.
Example:
<form>
<input type="text" name="date">
<select name="selection"></select>
</form>
and I want to init datepicker on the date element and Select2 on the selection element.
Where to put the form initialization?
My thoughts:
Init throught global selector:
$(function() {
$('input[name=date]').datepicker();
$('select[name=selection]').select2();
})`.
But I have one js file for the whole web, so this would led to crawling the whole DOM on each page load, even if the element is not present on current page.
Some kind of conditional selector. E.g. give <body> and id and add to my global js file something like this: $(function() { $('input[name=date]', 'body#foo').datepicker(); })
Encapsulate the init for each form into a function (or class method), and call the function from HTML:
<script type="text/javascript">
$(document).ready(initMyForm());
</script>
But I'm guessing, isn't there any better way? What would you suggest, especially for bigger projects with many different forms requiring different javascript initialization?
If for your current project you are running one JS file, or even for medium-size projects where a 'generic' form setup function is appropriate, using a function as you described would be appropriate.
See example below, with the function wrapped as a small jQuery plugin, so you can call this on specific selectors as required, to avoid running through the whole DOM.
;(function($){
$.extend({
initMyForm : function(){
$(this).find('input[name=date]').datepicker();
$(this).find('select[name=selection]').select2();
}
});
})(jQuery);
So you can use this like:
$(document).ready(function(){
$(body).find(form).initMyForm();
});
$("#my-form").initMyForm();
$(".page-content .form").initMyForm();
I have the following problem.
To translate a website, I'm using the jQuery Localize plugin.
This works fine. However, I want a CSS styled selectbox with flags and languages, and when a different option is selected the call to $("[data-localize]").localize("example", { language: $(this).attr('value') should be made to translate the page.
This code I'm currenly using, and it works fine for a plain, not-styled selectbox.
<script type="text/javascript">
$(function() {
$('#polyglot-language-options').change(function() {
if ($(this).attr('value') == "en") {
$("[data-localize]").localize("example", {
language: $(this).attr('value')
});
}
else if ($(this).attr('value') == "nl") {
location.reload();
}
});
});
</script>
But I want to style it, so I tried to integrate the "polyglot" language switcher. However, the current code doesn't work.
How can I integrate the $("[data.localize]").localize(); function in this code:
$('#polyglotLanguageSwitcher').polyglotLanguageSwitcher({
effect: 'fade'
});
This plugin (source code) does not follow the guidelines for jQuery plugin design. The bugs I found quickly:
It does not allow chaining, because it does not return this
It works only on one element at a time (does not use each())
It has a queer element hierarchy. It seems to require an element with an id, containing a form containing a select (as in the demo). In my opinion, such a plugin should be called on the language select element only.
It seems to navigate automatically, wanting to be configured with the page structure. Each of the li items in that fancy box contains a link to the respective page.
Therefore, it does neither trigger the form it live in or fire the change event you want to listen to.
As it stands, you can't use this particular plugin as you want to. If you want to fix all the bugs, I wish you a happy time :-) Nonetheless it might be possible to manipulate the plugin code, to let you register callbacks on select events (where you can invoke the localisation plugin). Otherwise, you will need to choose an other select plugin (or build one yourself from scratch, adapting the existing code)
I'm having trouble with the Dojo documentation (as usual).
On their TabContainer API, they list the second argument as an object called "params", but they never say what you can actually put in this params object. Can I specify the width? The height? Do I specify the id's of the divs I want to be the tabs inside the container?
There's also no specification of what attributes I would put in HTML if I wanted to specify the tab containers to be parsed by the Dojo parser. I found the following example that lets you put the title, selected and closable options. Is there anything else?
<div id="tabA1" dojoType="dijit.layout.ContentPane" title="First Tab" selected="true" closable="true">
First Tab
</div>
<div id="tabA2" dojoType="dijit.layout.ContentPane" title="Second Tab" closable="true">
Second Tab
</div>
<div id="tabA3" dojoType="dijit.layout.ContentPane" title="Third Tab" closable="true">
Third Tab
</div>
</div>
I am not an expert in Dojo widgets, but this is what I know:
All Dojo widget constructors have signature:
var widget = new Widget(params, node);
The best way to discover params is to look at the source code — don't get scared, they would be documented variables at the beginning of a relevant class.
The relevant file is usually simple to find using the name of the widget because they are named by their path.
The best way to look up this stuff is to use a Dojo checkout with your favorite text editor. But the nightly checkout works too (if you follow the trunk). Or the Trac source browser.
Don't underestimate the power of looking at tests and demos.
Example: dijit.layout.TabContainer ⇒ dijit/layout/TabContainer.js. If the file is missing look into directories of the hierarchy for _base.js, or some similarly sounding files — the latter can bundle related classes together. But in most cases (like with TabContainer) you'll find it immediately. Let's go and look.
There are two public documented parameters in the top of the class:
tabPosition — String. Defines where tabs go relative to tab content. "top", "bottom", "left-h", "right-h". Default: "top".
tabStrip — bool. Defines whether the tablist gets an extra class for layouting. Default: false.
_controllerWidget — just ignore it, no public parameters start with the underscore — it is a common JavaScript convention to designate protected members.
But it is not all. TabContainer is based on dijit.layout.StackContainer (just look at the dojo.declare() header). We can use StackContainer's public parameters as well:
doLayout — Boolean. If true, change the size of my currently displayed child to match my size. Default: true.
persist — Boolean. Remembers the selected child across sessions. Default: false.
As you can see the code and parametrs are nicely documented, yet not always reflected in the API tool. Now we can create the tab container with confidence.
But let's see it in action first. All Dijit tests are always in dijit/tests. Any dijit.layout.* widget will be tested in dijit/tests/layout. The relevant test file would be named something like test_TabContainer.html, and in fact I see 5 files for that:
test_TabContainer.html.
test_TabContainer_noLayout.html.
test_TabContainer_prog.html.
test_TabContainer_remote.html.
test_TabContainerTitlePane.html.
For example, let's recreate the first TabContainer of test_TabContainer.html:
var tc = new dijit.layout.TabContainer(
{persist: true, tabStrip: true}, "mainTabContainer");
Or we can do it like in the test inline:
<div id="mainTabContainer" dojoType="dijit.layout.TabContainer"
persist="true" tabStrip="true" style="width: 100%; height: 20em;">
...
</div>
Coming back to your original question: now you can see that width and height are specified simply as styles, no special attributes, nothing fancy, just some intuitive CSS. So if you want to do it programmatically, just set them on a node before creating a new instance of TabContainer.
Yeah, I wish the API doc got all these small details too, but the whole setup is intuitive, and relevant parts are documented right in the file. We did go to the source code, but we didn't try to decipher the source code, just read human-readable comments on the top of the class.