Dynamically loading widgets in Dojo ContentPanes - javascript

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.

Related

How to load multiple CKEditor toolbars on the same web page

I have two divs on the same page using CKEditor. I can get a toolbar to load for the first div, but not the second. I realize this is the case because I'm using an id for ckToolbar instead of a class. However, if I use a class, the toolbar doesn't show up.
Div 1
<div id="ckEditor">
<div id="ckToolbar"></div>
<div class="editor" data-bind="wysiwyg: txtBody, value:txtBody, valueUpdate:'keydown'"></div>
</div>
Div 2
<div id="ckEditor">
<div id="ckToolbar"></div>
<div class="editor" data-bind="wysiwyg: txtHelpText, value:txtHelpText, valueUpdate:'keydown'"></div>
</div>
Config.js
config.extraPlugins = 'sharedspace';
config.sharedSpaces = { top: 'ckToolbar' };
I am also using Knockout JS. I created a custom binding and a div instead of a textarea because I couldn't use the CKEDITOR replace function with my binding.
You can't have two elements on the same page with same id's. How is JavaScript supposed to recognize which one you have in mind? You should either use classes or different id's and adjust you knockout code to handle that.
Sorry for the general answer but there is simply no way around it. You can't have two elements with same id on a single page.
NOTE: CKEditor auto replaces elements with ckeditor class however if you are using knockout, I don't think this will me much of a use for you.

How to tell if an element is a jquery-ui widget?

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
}

Minimal jQuery template

I am creating a UI, in which user can add / delete items (of similar layout).
It starts with one item and you can click 'add' to add more. The UI consists of several different types of items.
What I am doing currently is populating a single item item 1 ( of each type ) and on add event, I clone the item 1, replace the changes done by user in item 1 and append the clone to the container.
In simple words, instead of dynamically creating html with jQuery, I am cloning html of a div. But in this approach , I had to change a lot of things to keep to give the new item to initial state.
So, I want to avoid the replacing the edits done by user, so I was thinking something like below,
<script type="text/template" id="item_type1">
<div>
<div>Box</div>
</div>
</script>
<script type="text/template" id="item_type2">
<div>
<div>Box2</div>
</div>
</script>
And on add event, I want to do something like $('#item_type1').html() and $('#item_type2') to create new items.
I know there are sophisticated libraries like handlebar and mustache and underscore has its own way of implementing templates.
But I am not using any of these already and thus do not want to included them just to copy content. I dont want anything special. I am not passing variables. I am just cloning some markup to use again and again.
Is this way to insert html in script tags , going to work in all browsers ? and is it a good way ?
EDIT:
Its for the wp plugin and I assume js is turned on , else the plugin wont work anyways.
What about:
Your HTML should be, for example:
<script type="text/template" id="item_type1">
<div>
<h1>Box1</h1>
<p>
</p>
</div>
</script>
And your code would be:
var templateHtml = $('#item_type1').html();
var $item = $(templateHtml);
$('body').append($item);
$item.on('click', function() {});
This is an easy way that will work on all browsers.
Step 1: Create an HTML file with your template inside of it
Step 2: Using jQuery's load() method, call your HTML template into a div element in the main HTML file:
$("#main-div").load("yourtemplate.html")
Step 3: Be amazed
Is this a good idea? It depends:
If it's a self contained application on a known environment with a determined supported browser and with equally determined settings (like if JavaScript is on or not) then yea, sure. Why not?
If it's open to the public in every single browser possible with many different configurations, then no, it's a horrible idea. If your user doesn't have JavaScript enabled, then your content doesn't show up. Also, if one of your scripts break in production, then you are again left with no content. You can learn this lesson from when Gawker made this same mistake

dijit.findWidgets return null array?

On the JSTL page I have following divs
<div dojoType="dijit.layout.TabContainer" style="width: 100%; height: 100%;" doLayout="false" id="dojoTabbedPane" >
<c:forEach items="${summariesMap}" var="summaryEntry">
<div dojoType="dijit.layout.ContentPane" title="${summaryEntry.key}">
I try to find all divs under (including dojoTabbedPane) in order to recersively destroy all the contentPane under it. Then I can use jQuery.load() to reload contents and use
dojo.parser.parse(dijit.byId("dojoTabbedPane"));
to re-parse the component to make sure the tabbedPane can be rendered(otherwise it doesn't and cause memory leak or error)
Here the question is:
(1) Am I on the right track to re-parse the dojo TabbedContainer?
(2) Why each time the findWidgets function just return array with size 0?
Thanks in advance.
I'll answer 2 first: because dijit.findWidgets expects a DOM node, not a widget. If you need to find all widgets inside another widget, you can use getDescendants instead:
var descWidgets = dijit.byId("dojoTabbedPane").getDescendants();
Onto question 1: First off: if you want to destroy all the tabs in a TabContainer, you can use :
dijit.byId("dojoTabbedPane").destroyDescendants();
Now, if I understand you correctly, you subsequently grab a string of HTML from the server (using jQuery), and want to add it to the TabContainer. This new content contains several ContentPane divs, and you want these to become the new tabs in the TabContainer.
I may be wrong here, but I don't think that's doable without some gnarly hack. Once you've parsed/instantiated a TabContainer, you should add tabs using addChild, passing instantiated ContentPanes.
This means that if you get new HTML content like this from the server (via your jQuery load):
<div dojoType="dijit.layout.ContentPane" title="new tab1">foo</div>
<div dojoType="dijit.layout.ContentPane" title="new tab2">bar</div>
.. then your best bet is to remove the old TabContainer and make a new one, then parse the whole thing. If you're able to change the content you get from your server, perhaps you can simply wrap that in <div dojoType="dijit.layout.TabContainer....

Connect links inside an dijit.dialog

i have some trouble to connect an link inside an dijit.dialog.
Iam calling an "other" html file inside the Dialog (dialog.href="xxx.html") inside this file iam trying to connect some links by id, to fire an alert box. But nothing happens ? Possible that this isnt possible ??
Thats the part from my xxx.html file..
<script type="text/javascript">
dojo.addOnLoad(function( ) {
dojo.connect(dojo.byId('testLink'), 'onClick', alert('xx'));
}); </script>
TEST
Dialog is extended from ContentPane so it supports all the same parameters (href, etc.). With that said, when a page is included via the href property any <script> tags are not evaluated they are just added to the DOM. This leaves you with two choices:
refactor xxx.html, so the script can be run by the dialog's onLoad handler
embed the event handlers into the html tags; i.e. <input type="button" onClick="alert('xx');" />
Another option would be to use dojox.layout.ContentPane. It'll parse <script> tags. It's in dojox though so it's liable to change in future version. And another downside is that this would require creating your own Dialog class that's a subclass of dojox.layout.ContentPane.
There's also an article on dojocampus about executing javascript in content panes which talks a little bit about using dojox.layout.ContentPane to roll your own Dialog widgets.

Categories

Resources