Dojo: defining Select-like widget with Options declaratively - javascript

The goal is to write custom widget similar to Select with options. Options should be able to be specified declarative. Example:
<div data-dojo-type="MySelect">
<span class="my-select-option" data-dojo-type="MySelectOption>Foo</span>
<span class="my-select-option" data-dojo-type="MySelectOption>Bar</span>
</div>
The problem is that all <span>s get overwritten and removed. What is the way to handle them correctly inside MySelect's JavaScript file?

You can use data-dojo-props together with dojo/parser to decoratively configure your custom widget.
Here a quick example for a possible markup, please note:
Use data-dojo-type to specify your custom "class" for your widget.
Use data-dojo-props to pass to the constructor any sort of configuration information upon instantiation.
data-dojo-props is a HTML5 data attributes and works with the latest version of Dojo.
Markup in your HTML:
<div id="instanceId" data-dojo-type="nameSpace/class" data-dojo-props="data: 'some data'"></div>
This reading is a good start:
https://dojotoolkit.org/documentation/tutorials/1.10/declarative/
For more information about parsing:
https://dojotoolkit.org/reference-guide/1.10/dojo/parser.html

Related

Angular2: Dynamically create view selector based on model property?

I've been a C/C++ coder for a long time, but am new to Angular2 and TypeScript. I have a TypeScript class (call it Node) which has a type: string property that specifies what sort of node it is. (The data comes as JSON from a server, and is basically being parsed out as a syntax tree.)
What I'm doing now in the view template in order to choose the view for each Node object is using an ngSwitch to check the value of node.type, and then inserting the appropriate selector using ngSwitchCase for each possible case, e.g.:
<div [ngSwitch]="node.type">
<node-type-a-view *ngSwitchCase="'a'" [(node)]="node"></node-type-a-view>
<node-type-b-view *ngSwitchCase="'b'" [(node)]="node"></node-type-a-view>
<node-type-c-view *ngSwitchCase="'c'" [(node)]="node"></node-type-a-view>
<div class="debug" *ngSwitchDefault>
TODO: View for type "{{node.type}}" is missing
</div>
</div>
The problem is that there are over a hundred different node types, and so this is going to be very unwieldy, very quickly.
What I'd like to do is something like this (but obviously this doesn't work in Angular2):
<node-type-{{node.type}}-view [(node)]="node"></node-type-{{node.type}}-view>
Or, using an attribute selector:
<div node-type-{{node.type}}-view [(node)]="node"></div>
Is there any functionality that comes close to what I'm looking for? I don't need to dynamically create the node-type-*-view views themselves, just the template that references them.
Also, apologies if I'm getting this architecture completely wrong. I'm still wrapping my head around the way Angular2 does things!
Thanks for any assistance you can give!

Is there a way to unit-test unobstrusive jQuery scenarios

I would like to test if certain javascript (using jQuery or any other framework) applied to a certain html code would create certain behaviour on a page. For example:
If I have html (written in a test as a stub)
<div class="order">
<div class="id">15</div>
<div class="client">John</div>
</div>
And I have a js files included (written in a test also):
jquery.js
orders.js (the one I want to test)
And the main part of the test (syntax is imagined)
part 1:
'client'.is 'hidden'
part 2:
'order'.click
'client'.should_be visible
I want the test to pass only if orders.js has this code:
$(function(){
$('.client').hide();
$('.order').click(function(){
$(this).children('.client').show();
});
});
I guess, I can do such things with rspec features or cucumber, but is there any more specific frameworks for such tests? Any help would be appreciated.
There are at least two solutions.
First is jasmine-jquery HTML fixtures. Citation:
The Fixture module of jasmine-jquery allows you to load HTML content
to be used by your tests. The overall workflow is as follows:
In myfixture.html file:
<div id="my-fixture">some complex content here</div>
Inside your test:
loadFixtures('myfixture.html')
$('#my-fixture').myTestedPlugin()
expect($('#my-fixture')).to...
and
Also, a helper method for creating HTML elements for your tests is
provided:
sandbox([{attributeName: value[, attributeName: value, ...]}])
It creates an empty DIV element with a default id="sandbox". If a hash of
attributes is provided, they will be set for this DIV tag. If a hash
of attributes contains id attribute it will override the default
value. Custom attributes can also be set.
And also there is jasmine-fixtures library. Citation:
Let's say you want to write a Jasmine spec for some code that needs to
select elements from the DOM with jQuery:
$('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')
...
jasmine-fixture's affix method lets you do this instead:
beforeEach(function(){
affix('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')
});

jQuery Metadata selector

Hi I have lot of divs like this
<div class="card {toggle:'A'}">
<div class="card {toggle:'B'}">
<div class="card {toggle:'C'}">
<div class="card {toggle:'D'}">
Now I want to hide eg. B DIV. Im trying to
$(.class [toggle:A]).hide();
or some other combination, but nothig was working. Could you suggest any solution. Im using "Metadata - jQuery plugin for parsing metadata from elements".
Thanks a lot
EDIT
I didn't realize you were using the metadata plugin. You should be able to do something like
$("div.card").forEach(function(element) {
if (element.metadata().toggle === 'B') {
element.hide();
}
});
EDIT 2
The metadata plugin was deprecated in 2011:
"The Metadata plugin will be deprecated, in favor of similar
functionality provided by jQuery 1.4.3 and above."
Use jQuery's own .data() instead.
ORIGINAL
This seems like you're doing something wrong upstream. Why are you storing data in the class attribute? One option to consider is to use jquery's .data() to store stuff. I strongly suggest you take a look at doing something like that.
However, if you want to blindly plunge forward, I can help. CSS supports attribute selectors. In this case, you can use the [rel$=foo] form to match against the end of the class attribute:
$('div[class$="B\'}"]')
Note the messy escape characters involved.
A better solution is probably to use the [rel*=foo] form to match anywhere in the attribute:
$('div[class*="toggle:\'B\'"]')
I've made an example here:
http://jsfiddle.net/pabo/pxg0v8uq/
You can read a nice easy guide to attribute selectors here: http://css-tricks.com/attribute-selectors/

Dynamically loading widgets in Dojo ContentPanes

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.

Dojo Parameters for Tabs

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.

Categories

Resources