Dojo : Layout widgets inside the Custom widget - javascript

I have a Custom dojo widget with dojo layout widgets
template as below
<div>
<div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="gutters:false" id="mainPanel" style="padding: 0px">
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top', splitter:false" style="padding: 0px">
Saartha Labs Pvt Ltd
</div>
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top', gutters: false, splitter:false" style="padding: 0px" >
<div id="toolBar"></div>
</div>
<div id="map-div" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center', splitter:false"></div>
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'bottom', splitter:false" style="display: none" ></div>
</div>
</div>
and the Custom Widget as below "Canvas.js"
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_WidgetsInTemplateMixin",
"dijit/_OnDijitClickMixin",
"dijit/_TemplatedMixin",
"dojo/text!./canvas.html",
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane"
], function (declare, _WidgetBase,_WidgetsInTemplateMixin, _OnDijitClickMixin,_TemplatedMixin, template) {
return declare([_WidgetBase,_OnDijitClickMixin, _TemplatedMixin,_WidgetsInTemplateMixin], {
templateString: template
//  your custom code goes here
});
});
When use try to use the Canvas with new
it throws a error as below.
require([
"bhuvi/canvas/Canvas",
"dojo/domReady!"],
function(Canvas){
var canvas = new Canvas();
canvas.placeAt(window.document.body);
});
Error as
"Tried to register widget with id==mainPanel but that id is already registered"

Never use IDs in your widget templates. IDs must be unique, so unless your ID is dynamically generated (which isn't in this case), your ID won't be unique if you create multiple instances of your widget.
In stead of that, use the data-dojo-attach-point mechanism, for example:
<div>
<div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="gutters:false"
data-dojo-attach-point="mainPanel" style="padding: 0px">
<!-- Rest of the code -->
</div>
</div>
Now you can use this.mainPanel if you need access to that widget.
Even if you don't create multiple instances of your widget, you're still better off by using the attach points, you never know what happens behind the screens.
A small side note: Layout widgets are not officially supported by the dijit/_WidgetsInTemplateMixin mixin, so be careful when using them. However, this is not the cause of your problem.

var dojoConfig = {
async: true,
parseOnLoad: false
}
parseOnLoad should be false

Related

Problem trying to select next item in JQuery

I'm trying to select the next element to add the class image-radio-selected with JQuery.
My html is like
<div id="photocall">
#foreach ($photocalls as $photocall)
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
#endforeach
<input>
</div>
Im trying to:
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected'); // working
selected.next('.photocallThumb').addClass('image-radio-selected'); // not working
});
After 2 hours, trying to solve, reading doc,
I'm more confused than when I started...
what am I doing wrong?
One method is you will need to get out of the parent div, then do a next for the parent.
$( "#mybutton" ).on("click", function() {
var selected = $('.photocallThumb.image-radio-selected');
selected.parent(".d-inline-block").next(".d-inline-block").find('.photocallThumb').addClass('image-radio-selected'); // not working
});
.image-radio-selected{border:1px solid #ff00aa;}
.mx-1{width:100px;height:100px;border:1px solid #000000;}
.d-inline-block{display:inline-block;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="photocall">
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb image-radio-selected"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<div class="d-inline-block mx-1">
<div style="background-image: url('')" class="photocallThumb"></div>
</div>
<button type="button" id="mybutton">next</button>
</div>
JQuery's next method selects the next sibling of the selected element. However, since your photocallThumb div is inside a d-inline-block div, it has no siblings. You'd have to go back up a level, then find the next photocallThumb, maybe something like selected.parent().find('.photocallThumb').eq(0).
However, an even better pattern that will help you avoid bugs like these is called templating. Basically, on the client side, you have an html template string, and you pass it data that represent your current state. In your case, you'd pass it an array of javascript objects, each one with an image url and an isSelected boolean. Then, when your state changes, instead of using jquery to try to fix what's changed, you just rerender your template and replace your html element's content with the newly rendered template, and it's now magically in the correct state. This is the pattern favored by large frameworks like React and Angular.
Here's an example from lodash that renders a list of usernames:
// Use the "evaluate" delimiter to execute JavaScript and generate HTML.
var compiled = _.template(
`<% _.forEach(users, function(user) { %>
<li><%- user %></li>
<% }); %>`);
compiled({ 'users': ['fred', 'barney'] });
// => '<li>fred</li><li>barney</li>'

change label color of one tab in a series of tabs in dijit layout tabcontainer

I'm trying to change the label color of a tab in a dijit/layout/tabcontainer to distinguish it from other tabs, but I'm not having any luck.
I've got this HTML:
<div data-dojo-type="dijit/layout/TabContainer" data-dojo-props="region:'center'" id="tc" >
<div data-dojo-type="dijit/layout/ContentPane" title="Start" id="Start" class="TabBackground"></div>
<!--bunch more tabs here-->
<div data-dojo-type="dijit/layout/ContentPane" title="Attachments" id="Attachments" class="TabProp1Fund"></div>
<div data-dojo-type="dijit/layout/ContentPane" title="Finish" id="Finish" class="TabBackground"></div>
</div>
Trying css:
.TabProp1Fund .dijitTab .tabLabel{ //saw this style when inspecting element
color:orange !important;
}
also tried:
.TabProp1Fund .tabLabel{
color:orange !important;
}
Trying javascript:
var TabAttachments = dojo.byId("Attachments");
TabAttachments.dijitTab.tabLabel.style.color="green";//dijitTab and tabLabel are undefined
any ideas what I'm missing ? I'd actually prefer to change the tab color, but I dont know if there is a property for this?
Thanks
This is because the class is not replicated in the generated Tab menus , it remains only in the content pane div , but the you can do it dynamically by searching (in ready after dom load ) using the class for your content pane , get it's ID and apply the color , class or whatever you want to a "tc_tablist_"+contentePaneID in order to apply this to all content pane having your specified class . (using dojo/dom-style)
See below working snippet :
Below I applied color directly to dom , but it's better to create class , and add it using "dojo/dom-class" domClass.add("someNode", "newClass");
require([
"dojo/query",
"dojo/on",
"dojo/dom",
"dojo/dom-style",
"dojo/ready",
"dijit/layout/TabContainer",
"dijit/layout/ContentPane",
"dojo/domReady!"
], function(query, On, dom, domStyle, ready, TabContainer, ContentPane) {
ready(function() {
query(".TabProp1Fund").forEach(function(element) {
console.log(element.id)
var textNode = dom.byId("tc_tablist_"+element.id);
console.log(textNode)
if (!textNode) return;
domStyle.set(textNode, {
color: "orange"
});
});
});
});
<script>
dojoConfig = {
async: true,
parseOnLoad: true
}
</script>
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.11.2/dojo/dojo.js"></script>
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.10.0/dijit/themes/claro/claro.css" rel="stylesheet" />
<div class="claro">
<div data-dojo-type="dijit/layout/TabContainer" data-dojo-props="region:'center'" id="tc">
<div data-dojo-type="dijit/layout/ContentPane" title="Start" id="Start" class="TabBackground"></div>
<!--bunch more tabs here-->
<div data-dojo-type="dijit/layout/ContentPane" title="Attachments" id="Attachments" class="TabProp1Fund"></div>
<div data-dojo-type="dijit/layout/ContentPane" title="Finish" id="Finish" class="TabBackground"></div>
<div data-dojo-type="dijit/layout/ContentPane" title="Another orange" id="another" class="TabProp1Fund"></div>
</div>
</div>

Translate JQuery Mobile widgets

Using i18next, how can I translate JQuery Mobile widgets? Specifically, I'd like to know how to do that without resorting to using data-i18n-target to modify generated inner elements, because that is brittle since future widget versions may change the generated code.
Is there a specific page lifecycle event I can subscribe to in order to be able to have i18next modify the DOM before the widget transformation happens?
In this example (see jsfiddle), some markup is correctly translated, but homeBtn and submitBtn are not:
HTML:
<div id="home_page" data-role="page">
<div data-role="header">
<a id="homeBtn" href="/" data-icon="home" data-i18n>app.home</a>
<h2 data-i18n>app.title</h2>
</div>
<div data-role="content">
<div data-role="fieldcontain">
<label for="textinput1" data-i18n>app.label</label>
<input type="text" name="textinput1" id="textinput1" value=""></input>
</div>
<form action="">
<input id="submitBtn" type="submit" data-i18n="[value]app.button" />
</form>
</div>
<div data-role="footer">
<center>
<p data-i18n>app.footer</p>
</center>
</div>
</div>
JavaScript:
var i18nOpts = {
resStore: {
dev: {
translation: {
app: {
button: 'Button',
home: 'Home',
label: 'Label',
footer: 'Footer',
title: 'i18n Test'
}
}
},
}
};
i18n.init(i18nOpts).done(function() {
$("html").i18n();
});
jQuery Mobile widgets are auto-initialized (Markup enhancement) on two events, pagebeforecreate and pagecreate. The majority of widgets are initialized once pagecreate occurs.
All you need is to wrap i18n code in pagebeforecreate.
$(document).on("pagebeforecreate", function () {
// code
});
Demo

Popup using knockout js

i'm migrating one of my older jquery plugins from DOM jungle to this fancy mvvm framework knockout.
Which technique would i use to properly display a popup container? I ahve to populate it 'by call' since i get a json feed every time.
I tried an approach using the with binding, but it still attempts to populate the partial at its first runtime.
<!-- ko with: daySubmitFormViewModel -->
<div class="ec-consulation-lightbox">
<form id="cForm" class="form-container">
// Some bindings here.
</form>
</div>
<!-- /ko with: -->
It can be done without custom binding as well. Example is below
<div class="modalWindowBackground" data-bind="visible: popupDialog" >
<div class="modalWindow" data-bind="with:popupDialog">
<div class="content">
<h2 data-bind="text: title"></h2>
<p>
<span data-bind="text: message"></span>
</p>
<div class="buttonSpace">
<input type="button" class="closeButton" data-bind="value: closeButtonText, click: $root.hidePopupDialog" />
</div>
</div>
</div>
</div>
Viewmodel code:
self.showAlert = function (title, message, closeButtonText) {
self.popupDialog({ title: title, message: message, closeButtonText: closeButtonText });
};
self.hidePopupDialog = function () {
self.popupDialog(null);
};
//Code which opens a popup
self.remove = function () {
.... some code ...
if (someCondition) {
self.showAlert('SomeTitle', 'Message', 'OK');
return;
}
.... some code ...
};
Create a custom binding, have its open / close function trigger on a observable.
I've done a custom binding for jQuery Dialog that uses this approuch in combination with KO
templates.
<div id="dialog" data-bind="dialog: { autoOpen: false, modal: true, title: dialogTitle }, template: { name: 'dialog-template', data: dialogItem, 'if': dialogItem }, openDialog: dialogItem"></div>
You can find my binding here along with some others
https://github.com/AndersMalmgren/Knockout.Bindings
Live demo http://jsfiddle.net/H8xWY/102/
https://github.com/One-com/knockout-popupTemplate
That pretty much does what you ask for. It's deeply configurable, and under steady development (we use it in our web applications ourselves).
Disclaimer: I'm a One.com developer. I am also the person who originated the above mentioned lib.

Adding content to dijit Dialog

I've looked at quite a few links for people trying to add content / change the template for a Dojo Dialog. This was the most promising.
However, whenever I do something like this:
Dialog declared in HTML:
<div class="djDialog" id="dgViewer" data-dojo-type="TemplatedDialog" data-dojo-props="title: 'My Dialog', draggable:false"></div>
Dialog Template:
<div class="dijitDialog" role="dialog" aria-labelledby="${id}_title">
<div data-dojo-attach-point="titleBar" class="dijitDialogTitleBar">
<span data-dojo-attach-point="titleNode" class="dijitDialogTitle" id="${id}_title"></span>
<span data-dojo-attach-point="closeButtonNode" class="dijitDialogCloseIcon" data-dojo-attach-event="ondijitclick: onCancel" title="${buttonCancel}" role="button" tabIndex="-1">
<span data-dojo-attach-point="closeText" class="closeText" title="${buttonCancel}">x</span>
</span>
</div>
<!-- containerNode from original Dialog template -->
<div data-dojo-attach-point="containerNode" class="dijitDialogPaneContent">
<!-- All "custom" content -->
<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design:'headline'" style="height:300px">
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center'">
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'">
<button data-dojo-type="dijit.form.Button">Edit</button>
<button data-dojo-type="dijit.form.Button">Status</button>
</div>
</div>
<!-- End "custom" content -->
</div>
</div>
Custom Dialog class:
define([
'dojo/_base/declare',
'dijit/Dialog',
'dijit/_TemplatedMixin',
'dojo/text!./dialog_templates/View.html'],
function(
declare,
Dialog,
_Mixin,
_template){
return declare('TemplatedDialog', [Dialog, _Mixin], {
templateString : _template,
constructor : function(){
}
})
})
In my console (using Chrome) I just see:
<div data-dojo-attach-point="containerNode" class="dijitDialogPaneContent" style="width: auto; height: auto; "></div>
... and empty node where content should be.
So far I haven't found anyone who seems to have successfully extended dijit.Dialog in terms of templates. Is this possible?
Edit
After trying some variations on this template:
<div class="dijitDialog" role="dialog" aria-labelledby="${id}_title">
<div data-dojo-attach-point="titleBar" class="dijitDialogTitleBar">
<span data-dojo-attach-point="titleNode" class="dijitDialogTitle" id="${id}_title"></span>
<span data-dojo-attach-point="closeButtonNode" class="dijitDialogCloseIcon" data-dojo-attach-event="ondijitclick: onCancel" title="${buttonCancel}" role="button" tabIndex="-1">
<span data-dojo-attach-point="closeText" class="closeText" title="${buttonCancel}">x</span>
</span>
</div>
<!-- containerNode from original Dialog template -->
<div class="dijitDialogPaneContent">
<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design:'headline'" style="height:100%;width:100%">
<div data-dojo-attach-point="containerNode" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center'"></div>
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'bottom'">
<button data-dojo-type="dijit.form.Button">Edit</button>
</div>
</div>
</div>
The error Uncaught TypeError: Cannot read property '0' of undefined is being thrown. This is the stack, if it helps. I'm using the uncompressed version from the Google CDN to help in debugging.
_childElements dojo.js.uncompressed.js:8341
getStepQueryFunc dojo.js.uncompressed.js:8597
query dojo.js.uncompressed.js:9005
query dojo.js.uncompressed.js:5248
_2._checkIfSingleChild _ContentPaneResizeMixin.js:2
_4._size Dialog.js:2
_4.show Dialog.js:2
Removing the data-dojo-type and -props from the containerNode resolves this, but it's still not getting things closer to having a working custom templated Dialog.
Reason for troubles with doing templating on a contentpane is, that whatever template-contents you put into the domNode referenced with the attach-point 'containerNode', you will loose on startup.
If there is no 'href' nor 'content' attributes set, they will simply be set to an empty string, thus leaving the Dialog.containerNode.innerHTML == ""
You have no need for deriving from _TemplatedMixin as the Dialog itself is a templated widget. Instead change this to _WidgetsInTemplateMixin to compensate for the BorderContainer layout widgets and your dijit.form contents. Also, your markup within the custom template should be pre-required, so you could go with something like this here:
Change the template from old attachpoint for container to this
<div data-dojo-attach-point="containerNode"
data-dojo-type="dijit.layout.ContentPane"
data-dojo-props="region:'center'">
Then add requirements to your markup widgets in the template plus the _WidgetsInTemplateMixin:
define(["dijit/Dialog",
"dijit/_WidgetsInTemplateMixin",
"dojo/text!./dialog_templates/View.html",
// rest are for rendering example
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane",
"dijit/form/Button"
}. ... );
Result should ressemble this, keeping your template View.html change in mind:
define([
'dojo/_base/declare',
'dijit/Dialog',
"dijit/_WidgetsInTemplateMixin",
"dojo/text!./dialog_templates/View.html",
// rest are for rendering example
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane",
"dijit/form/Button"],
function(
declare,
Dialog,
_Mixin,
_template){
return declare('TemplatedDialog', [Dialog, _Mixin /*careful, widgetsintemplate is tricky*/ ], {
templateString : _template
})
})
You can fiddle here
EDIT:
As there is troubles with dialogs containing borderlayouts (its not unheard of anyways) here's a workaround:
_checkIfSingleChild: function() {
delete this._singleChild;
domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
},
templateString: '....'
Im not certain of the consequences, im thinking the borderlayout of yours might start to misbehave if you try to programmatically change its contents and dimensions.. But it will render - at least it does here: updated fiddle

Categories