Difference between id and data-dojo-id - dojo

What is the difference between an id and a data-dojo-id in a dojo tag such as this:
<button id="save" data-dojo-type="dijit/form/Button" type="button" data-dojo-attach-event="onClick:save">Save</button>
I try to reference this button to change it's label with:
var myButton = dijit.byId("save");
so that I can change the button label
myButton.set("label", "Add New");
If I use id="save" it works. If I only use data-dojo-id="save" it doesn't work.
I'm fairly new to Dojo so an explanation or tutorial you can point me to would be much appreciated!

data-dojo-id assigns widget into global namespace, i.e. into window object:
<button data-dojo-id="save" data-dojo-type="dijit/form/Button">Save</button>​
so you can access the button directly:
save.set("label", "Add New");
See the difference in action at jsFiddle: http://jsfiddle.net/phusick/7yV56/
EDIT: To answer your questions. I do not use data-dojo-id at all. It pollutes global namespace which is the direct opposite of what the AMD does. Anyway, you can still use something like widgets.save and widgets.rename to minimize the pollution:
<button data-dojo-id="widgets.save" data-dojo-type="dijit/form/Button">Save</button>​
<button data-dojo-id="widgets.rename" data-dojo-type="dijit/form/Button">Rename</button>​
IMO, data-dojo-id is there for progressive enhancement, not for fully-fledged applications.
data-dojo-id just assigns an instance to a variable, so with multiple dijits with the same data-dojo-id the variable will point to the last one assigned (i.e. it'll not be an array).
You can avoid extensive use of registry.byId writing your method to obtain widgets according to your needs. The best way to start is dijit/registy.findWidgets(rootNode, skipNode). Please also note, that dojo/parser.parse(rootNode, options) returns an array of instantiated objects, or more precisely:
Returns a blended object that is an array of the instantiated objects,
but also can include a promise that is resolved with the instantiated
objects. This is done for backwards compatibility. If the parser
auto-requires modules, it will always behave in a promise fashion and
parser.parse().then(function(instances){...}) should be used.
An example of a method I use to assign ContentPane's dijits into its widgets property, which is an object:
_attachTemplateWidgets: function(widgets) {
widgets = widgets || this.getChildren();
for(var each = 0; each < widgets.length; each++) {
var widget = widgets[each];
var attachPoint = widget.params.dojoAttachPoint;
if(attachPoint) {
this.widget[attachPoint] = widget;
}
var children = widget.getChildren();
if(children.length > 0) {
this._attachTemplateWidgets(children);
}
}
}
I put the entire class here: https://gist.github.com/3754324. I use this app.ui._Pane instead of dijit/layout/ContentPane.

Related

Identifying a Customized Built-In Element without an is= attribute

In my Chessly.github.io project I use Customized Built-In IMG Elements to define SVG chesspieces:
Question: How can I distinguish a regular IMG from a customized IMG?
document.body.append(
document.createElement("IMG", {
is: "white-queen"
});
);
This creates a chesspiece, but does not set the is= attribute
I now explicitly set the is= attribute myself, but since this attribute does nothing and can be set to any value (I use is as an observed attribute in my Custom Element code) it is not a solid way to distinguish IMG elements from Customized IMG elements when walking the DOM.
If I promote a pawn (replace the img src)
<img is=white-pawn/>
with element.setAttribute("is","white-queen")
How can I determine the piece originally was the white pawn?
It still is a white-pawn in the Custom Elements registry.
Am I overlooking something?
Simplified code (with basic SVG shape) in JSFiddle: https://jsfiddle.net/dannye/k0va2j76/
Update: Code (based on correct answer below)
let isExtendedElement = x =>
Object.getPrototypeOf(x).__proto__.constructor.name !== 'HTMLElement';
note! This does NOT catch Autonomous Custom Elements!
maybe better:
let isBaseElement = x =>
Object.getPrototypeOf(Object.getPrototypeOf(x)).__proto__.constructor.name=='Element';
I think adding explicitly the is attribute is the best solution for now.
Else you'll have to deal with the class reference. In your case:
yourElement.constructor === customElements.get( 'circle-image' )
yourElement.constructor === CircleImage //if it's the named class
This supposes that you know the name of the custom elements you want to check.
Else you'll have to go through the protoype chain:
CircleImage --> HTMLImageElement --> HTMLElement --> Element --> Node
If HTMLElement is only the father, it's a built-in element.
If HTMLElement is the grandfather (or grand-grand...), it's probably an extended build-in element.
update
If you use a named class you can also retrieve its name:
elem.constructor.name

Polymer 1.0 Data binding when object changes

I'm having trouble understanding how data-binding works now.
On my index page I've got an object (obtained as JSON from a RESTful service), which works just fine when applied to a custom element like:
<main-menu class="tiles-container ofvertical flex layout horizontal start"
menuitems="{{menuitems}}">
</main-menu>
var maintemplate = document.querySelector('#fulltemplate');
maintemplate.menuitems = JSON.parse(data.GetDesktopResult);
This works as expected, and when I load my page with different users, main-menu changes as it should to show each user's desktop configuration. (This menuitems object reflects position and size of each desktop module for each user).
Now, users used to be able to change their configuration on the go, and on Polymer 0.5 I had no problem with that, just changed my maintemplate.menuitems object and that was that, it was reflected on the template instantly.
As I migrated to Polymer 1.0, I realized changes on an object wouldn't change anything visible, it's much more complicated than this, but just doing this doesn't work:
<paper-icon-button id="iconback" icon="favorite" onClick="testing()"></paper-icon-button>
function testing(){
debugger;
maintemplate = document.querySelector('#fulltemplate');
maintemplate.menuitems[0][0].ModuleSize = 'smamodule';
}
The object changes but nothing happens on the screen until I save it to DB and reload the page.
Am I missing something /Do I need to do something else on Polymer 1.0 to have elements update when I change an object passed as a property?
Before you ask, I've got those properties setted as notify: true, it was the inly thing I found different, but still doesn't work
Thanks for reading!
EDIT:
this is the code menuitems is used in:
<template is="dom-repeat" items="{{menuitems}}" as="poscol">
<div class="positioncolum horizontal layout wrap flex">
<template is="dom-repeat" items="{{poscol}}" as="mitem" index-as="j">
<main-menu-item class$="{{setitemclass(mitem)}}"
mitem="{{mitem}}"
index="{{mitem.TotalOrder}}"
on-click="itemclick"
id$="{{setitemid(index, j)}}">
</main-menu-item>
</template>
</div>
</template>
main-menu-item is just set of divs which changes size and color based on this object properties
You need to use the mutation helper functions if you want to modify elements inside an object or array otherwise dom-repeat won't be notified about the changes (check the docs):
function testing(){
debugger;
maintemplate = document.querySelector('#fulltemplate');
this.set('maintemplate.0.0.ModuleSize', 'smamodule');
}

DojoX Mobile ListItem load HTML via AJAX and then remove from DOM

Let's say in a view I have a DojoX Mobile ListItem that is pulling an HTML view fragment into the DOM via AJAX and then transitioning to that view. Assume this is all working fine.
Now, I go back to the initial view that had that ListItem on it and click some other button that destroys that view node from the DOM. If I now click on that ListItem that previously loaded that view node into the DOM (which has now been removed), it will try to transition to a view that doesn't exist. It doesn't know that it has been removed.
Is there some type of way to tell a ListItem that it needs to fetch the HTML again because what was previously fetched no longer exists? I am not seeing anything about doing this in any documentation anywhere. I don't think a code sample is really necessary here, but I can provide a minimal one if necessary.
I went a different route and left the view exist in the DOM, and simply made a function that clears all sensitive data out of the view.
Okay, in this case, i guess you could hook the onShow function of your ListItem container(or any other onchange event). Create a listener for said handle to evaluate if your item needs reloading. Following is under the assumtion that it is the item.onclick contents showing - and not the label of your item which contains these informations
Or better yet, do all this during initialization so that your ListItem container will be an extended with custom onClick code.
Seems simple but may introduce some quirks, where/when/if you programatically change to this item, however here goes:
function checkItem() {
// figure out if DOM is present and if it should be
if( isLoggedIn() ) {
this.getChildren().forEach(function(listitem) {
if( dojo.query("#ID_TO_LOOK_FOR", listitem.domNode).length == 0 ) {
// this references the listItem, refresh contents.
// Note: this expects the listitem to be stateful, have no testing environment at time being but it should be
listitem.set("url", listitem.url);
}
});
}
}
Preferably, set this in your construct of the container for your ListItems
var listItemParent = new dojox.mobile.RoundRectList({
onShow : checkItem,
...
});
Or create listener
var listItemParent = dijit.byId('itemRegistryId');
// override onClick - calling inheritance chain once done
dojo.connect(listItemParent, "onClick", listItemParent, checkItem);

Problems in my AS2 Game

Hey guys, I'm trying to make a 2D Platform style game similar to this game below:
http://www.gameshed.com/Puzzle-Games/Blockdude/play.html
I have finished making most of the graphic, and areas, and collision, but our character is still not able to carry things. I'm confused as to what code to use so that my character can carry the blocks. I need help as to how to make our character carry blocks that are in front of him, provided that the blocks that don't have anything on top of it. This has been confusing me for a week now, and any help would be highly appreciated. :D
I fondly remember my first AS2 game. The best approach is probably an object oriented approach, as I will explain.
In AS2, there is a hittest method automatically built into objects. There is a good tutorial on Kirupa here:
http://www.kirupa.com/developer/actionscript/hittest.htm
also
http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00001314.html
First you'll want to generate your boxes using a Box class. Your class would need to look something like the following:
//Box.as pseudo-code
class Box {
var x_pos:Number;
var y_pos:Number;
var attachedToPlayer:Boolean;
function Box(_x:Number, _y:Number) {
this.x_pos = _x;
this.y_pos = _y;
}
//other code here
}
See this tutorial on how to attach a class to an object in the library:
http://www.articlesbase.com/videos/5min/86620312
To create a new Box, you'd then use something like
box1 = new Box(100,200);
// creates a box at position 100x,200y
However, you'll also want to store the blocks you want to pickup into some sort of array so you can loop through them. See http://www.tech-recipes.com/rx/1383/flash-actionscript-create-an-array-of-objects-from-a-unique-class/
Example:
//somewhere near the top of your main method, or whereever your main game loop is running from - note Box.as would need to be in the same folder
import Box;
//...then, somewhere before your game loop
//create an array to hold the objects
var boxArray:Array = new Array();
//create loop with i as the counter
for (var i=0; i<4; i++)
{
var _x:Number = 100 + i;
var _y:Number = 100 + i;
//create Box object
var box:Box = new Box();
//assign text to the first variable.
//push the object into the array
boxArray.push(box);
}
Similarly, you would need a class for your player, and to create a new Player object at the start of your game, e.g.
var player = new Player(0,0);
You could then run a hittest method for your player against the blocks in your array for the main game loop (i.e. the loop that updates your player's position and other game properties). There are probably more efficient ways of doing this, e.g. only looping for the blocks that are currently on the screen.
Once your array has been created, use a foreach loop to run a hittest against your player in your game's main loop, e.g.
//assuming you have an array called 'boxArray' and player object called 'player'
for(var box in boxArray){
if (player.hittest(box)) {
player.attachObjectMethod(box);
}
}
This is basically pseudo-code for "for every box that we have entered into the array, check if the player is touching the box. If the box is touching, use the box as the argument for a method in the player class (which I have arbitrarily called attachObjectMethod)".
In attachObjectMethod, you could then define some sort of behavior for attaching the box to the player. For example, you could create a get and set method(s) for the x and y position of your boxes inside the box class, along with a boolean called something useful like attachedToPlayer. When attachObjectMethod was called, it would set the box's boolean, e.g. in the Player class
//include Box.as at the top of the file
import Box;
//other methods, e.g. constructor
//somewhere is the Player.as class/file
public function attachObjectMethod (box:Box) {
box.setattachedToPlayer(true);
//you could also update fields on the player, but for now this is all we need
}
Now the attachedToPlayer boolean of the box the player has collided with would be true. Back in our game loop, we would then modify our loop to update the position of the boxes:
//assuming you have an array called 'boxArray' and player object called 'player'
for(var box in boxArray){
if (player.hittest(box)) {
player.attachObjectMethod(box);
}
box.updatePosition(player.get_Xpos, player.get_Ypos);
}
In our Box class, we now need to define 'updatePosition':
//Box.as pseudo-code
class Box {
var x_pos:Number;
var y_pos:Number;
var attachedToPlayer:Boolean;
function Box(box_x:Number, box_y:Number) {
this.x_pos = box_x;
this.y_pos = box_y;
}
public function updatePosition(_x:Number, _y:Number) {
if (this.attachedToPlayer) {
this.x_pos = _x;
this.y_pos = _y;
}
}
//other code here
}
As you can see we can pass the player's position, and update the box's position if the attachedToPlayer boolean has been set. Finally, we add a move method to the box:
public function move() {
if (this.attachedToPlayer) {
this._x = x_pos;
this._y = y_pos;
}
}
Examples of updating position:
http://www.swinburne.edu.au/design/tutorials/P-flash/T-How-to-smoothly-slide-objects-around-in-Flash/ID-17/
Finally, to make it all work we need to call the move method in the game loop:
//assuming you have an array called 'boxArray' and player object called 'player'
for(var box in boxArray){
if (player.hittest(box)) {
player.attachObjectMethod(box);
}
box.updatePosition(player.get_Xpos, player.get_Ypos);
box.move();
}
You have also specified that the blocks should only move with the player if they have nothing on top of them. When you call your attachedToPlayer method, you would also need to run a foreach loop inside the method between the box and the objects that might sit on top of the box. You should now have a fair idea from the above code how to do this.
I appreciate that this is quite a lengthy answer, and I haven't had an opportunity to test all the code (in fact I'm fairly positive I made a mistake somewhere) - don't hesitate to ask questions. My other advice is to understand the concepts thoroughly, and then write your own code one bit at a time.
Good luck!
The way I would do this is to design an individual hit test for each block he will be picking up, then code for the hit test to play a frame within the sprite's timeline of him carrying a block, and to play a frame within the block to be picked up's timeline of the block no longer at rest (disappeared?).
Good Luck if you're confused about what I've said just ask a little more about it and I'll try to help you if I can.

Dojo Dijit: Why does attr("required", true) fail to set the style "dijitRequired"? or Is there another class which indicates a Dijit is required?

As far as I can judge, the CSS-Rule "dijitRequired" is used to mark a required input field. Yet, this style is not set when I apply the "required"-Attribute to a dijit, for example, a date dijit:
The Dijit is built as follows:
<input dojoType="dijit.form.DateTextBox" class="l" id="datumsTestID" name="datumsTest" tabindex="5" value="2009-01-01" />
The Attribute is set with the following Javscript code
dijit.byId('datumsTestID').attr('required', true)
Am I doing something wrong or is the style "dijitRequired" not intended to be used as I assume?
For my purposes, I patched ValidationTextBox.js to set/unset the class, but is there a cleaner (meaning: more correct) way to set the class or can I style required fields using other attributes?
ValidationTextBox.js, Dojo 1.3, Line 116
_setRequiredAttr:function(_12){
this.required=_12;
if (_12) dojo.addClass(this.domNode, "dijitRequired");
else dojo.removeClass(this.domNode, "dijitRequired");
dijit.setWaiState(this.focusNode,"required",_12);
this._refreshState();
}
Hmm, I don't see that code in ValidationTextBox.js or anywhere else. My _setRequiredAttr() in 1.3 is:
_setRequiredAttr: function(/*Boolean*/ value){
this.required = value;
dijit.setWaiState(this.focusNode,"required", value);
this._refreshState();
}
Actually I don't see any references to dijitRequired at all, maybe that's something you added to your local copy?
Setting dijitRequired is not enough. dijit.form.DateTextBox has its own internal state. Even if required attribute is set, this widget display error only when it has been blurred. You can disable this mechanism using such subclass:
dojo.provide("my.DateTextBox");
dojo.require("dijit.form.DateTextBox");
dojo.declare("my.DateTextBox", dijit.form.DateTextBox, {
_setRequiredAttr: function(required){
this._hasBeenBlurred = true;
this.inherited(arguments);
}
});