DataGrid Dojo Not Working in Widget - dojo

I have a widget on dojo, but it does not display the datagrid. If I make the example outside the widget works. I see the code by firebug, you can not mistake, however, I can see the div inspect and there is nothing inside. The Builder runs, but does not load the grid in div.
Widget.js
define([ "dojo/_base/declare",
"dojo/text!./FormularioQCI.html",
"icm/base/_BaseWidget",
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dojox/grid/DataGrid",
"dojo/data/ObjectStore"
],
function(declare, template, _BaseWidget, JsonRest, Memory, Cache, DataGrid, ObjectStore){
return declare("icm.custom.pgwidget.formularioQCI.FormularioQCIWidget", [_BaseWidget], {
templateString: template,
widgetsInTemplate: true,
constructor: function(){
alert("X");
myStore = dojo.store.Cache(dojo.store.JsonRest({target:"rest/formularioQCI/get"}), dojo.store.Memory());
grid = new dojox.grid.DataGrid({
store: dataStore = dojo.data.ObjectStore({objectStore: myStore}),
structure: [
{name:"State Name", field:"name", width: "200px"},
{name:"Abbreviation", field:"abbreviation", width: "200px", editable: true}
]
}, "target-node-id"); // make sure you have a target HTML element with this id
grid.startup();
alert("Y");
dojo.query("#save").onclick(function(){
alert("X");
dataStore.save();
});
var id = 0;
dojo.query("#add").onclick(function(){
dataStore.newItem({
name: "col2-" + id,
abbreviation: "col3-" + id
});
id++;
});
},
/**
* #private destroys this widget
*/
destroy: function() {
//Do any custom clean up here
this.inherited(arguments);
}
});});
Widget.html
<div style="width: 100%; height: 100%;">
<div id="target-node-id">
</div>
<button id="save">Save
</button>
<button id="add">Add Linha
</button>
</div>

you need to write you code in the postCreate function.
Simplest way would be to replace the constructor keyword with postCreate.
The reason being that the "target-node-id" will not be available until the postCreate function call.
postCreate: function(){
this.inherited(arguments);
// Rest of your code here.
alert("X");
...
}

Related

How is the method Total being called in this example

I see in the code below how the list item's class and state is being modified but I don't understand where or how the total() method is being triggered. The total is added to the markup in the <span>{{total() | currency}}</span> but there is no click event or anything reactive that I see in the code that is bound to it.
<template>
<!-- v-cloak hides any un-compiled data bindings until the Vue instance is ready. -->
<form id="main" v-cloak>
<h1>Services</h1>
<ul>
<!-- Loop through the services array, assign a click handler, and set or
remove the "active" css class if needed -->
<li
v-for="service in services"
v-bind:key="service.id"
v-on:click="toggleActive(service)"
v-bind:class="{ 'active': service.active}">
<!-- Display the name and price for every entry in the array .
Vue.js has a built in currency filter for formatting the price -->
{{service.name}} <span>{{service.price | currency}}</span>
</li>
</ul>
<div class="total">
<!-- Calculate the total price of all chosen services. Format it as currency. -->
Total: <span>{{total() | currency}}</span>
</div>
</form>
</template>
<script>
export default {
name: 'OrderForm',
data(){
return{
// Define the model properties. The view will loop
// through the services array and genreate a li
// element for every one of its items.
services: [
{
name: 'Web Development',
price: 300,
active:true
},{
name: 'Design',
price: 400,
active:false
},{
name: 'Integration',
price: 250,
active:false
},{
name: 'Training',
price: 220,
active:false
}
]
}
},
// Functions we will be using.
methods: {
toggleActive: function(s){
s.active = !s.active;
},
total: function(){
var total = 0;
this.services.forEach(function(s){
if (s.active){
total+= s.price;
}
});
return total;
}
},
filters: {
currency: function(value) {
return '$' + value.toFixed(2);
}
}
}
</script>
EDIT:
Working example https://tutorialzine.com/2016/03/5-practical-examples-for-learning-vue-js
So I believe the explanation for what is happening is that data's services object is reactive. Since the total method is being bound to it, when the toggleActive method is being called, it is updating services which causes the total method to also be called.
From the docs here 'How Changes Are Tracked' https://v2.vuejs.org/v2/guide/reactivity.html
Every component instance has a corresponding watcher instance, which records any properties “touched” during the component’s render as dependencies. Later on when a dependency’s setter is triggered, it notifies the watcher, which in turn causes the component to re-render.
Often I find simplifying what is going on helps me understand it. If you did a very simplified version of above it might look like this.
<div id="app">
<button #click="increment">Increment by 1</button>
<p>{{total()}}</p>
</div>
new Vue({
el: "#app",
data: {
counter: 0,
},
methods: {
increment: function(){
this.counter += 1;
},
total: function(){
return this.counter;
}
}
})
working example: https://jsfiddle.net/skribe/yq4moz2e/10/
If you simplify it even further by putting the data property counter in the template, when its value changes, you would naturally expect the value in the template to also be updated. So this should help you understand why the total method gets called.
<div id="app">
<button #click="increment">Increment by 1</button>
<p>{{counter}}</p>
</div>
new Vue({
el: "#app",
data: {
counter: 0,
},
methods: {
increment: function(){
this.counter += 1;
},
}
})
working example: https://jsfiddle.net/skribe/yq4moz2e/6/
When you update the data, the template in the components rerendered. That means that the template will trigger all methods bind to the templates. You can see it by adding dynamic date for example.
<div id="app">
<button #click="increment">Increment by 1</button>
<p>{{total()}}</p>
<p>
// Date will be updated after clicking on increment:
{{date()}}
</p>
</div>
new Vue({
el: "#app",
data: {
counter: 0,
},
methods: {
increment: function(){
this.counter += 1;
},
total: function(){
return this.counter;
},
date: function() {
return new Date();
}
}
})

Using the same component template and updating the API data

I'm building a page that has a embeds a specific twitch stream video. I'm only displaying one video at the top of my page.
Twitch has an embed code that allows you to grab the channel you want to watch and it will display the embedded video and chat. It requires a div id to target the DOM to add the embedded video.
https://dev.twitch.tv/docs/embed/everything/
My problem is when I click on another page, that uses the same template, it doesn't replace the video. Rather, it adds another IFRAME embed video to the id. So every time I click on the page, it just adds another video to the div id.
I'm using the watch function to update other elements of the page. So when I click on another page, using the same template, the data updates correctly. Everything works and updates except for that embed video.
Is there a way to clear out that div id every time I click another another page? I apologize in advance. I've only been learning Vuejs for a couple of weeks now, and it's all rather new to me.
Here is why my template looks like:
<template>
<div class="video heading-title container">
<div class="streamWrapper">
<div class="row">
<div v-for="live in streams" class="col-12 stream-card">
<div class="twitch-vid-wrapper">
<div id="twitch-embed"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import appService from '../service.js'
import '../embedTwitch.min.js' // twitch video embed script
export default {
name: 'Video',
data: function() {
return {
id: this.$route.params.id,
streams: []
}
},
created() {
this.getFirstLiveStream()
this.getLiveStreams()
},
watch: {
'$route' (to, from) {
this.id = to.params.id
this.getLiveStreams()
this.getFirstLiveStream()
}
},
methods: {
getLiveStreams(game){
game = this.$route.params.id;
appService.getLiveStreams(game).then(data => {
this.live = data
});
},
getFirstLiveStream(game) {
game = this.$route.params.id;
appService.getFirstLiveStream(game).then(data => {
this.streams = data
let channelName = this.streams[0].channel.display_name
appService.getTwitchStream(channelName)
});
}
}
}
</script>
Here is the method I have in my service:
const appService = {
getFirstLiveStream(game) {
return new Promise((resolve) => {
axios.get('/kraken/streams/?sort=views&stream_type=live&game='+game)
.then((response) => {
// send variables to calc the offset
var total = response.data._total;
var query = this.calculateSingleOffset(game, total)
resolve(query)
})
})
},
getTwitchStream(channel) {
return setTimeout(function(){
new Twitch.Embed('twitch-embed', {
width: '100%',
height: 480,
channel: channel
});
}
, 500);
}
}
Thanks!
As I understood, what you need is how to assign different id for one twitch template inside each instance of the component.
The solution:
add one data property like twitchId
simply uses Date.now() to generate unique id (this method is just one demo, you can use own methods to get one ID).
then bind <div :id="twitchId"> which will embed into twitch video.
Vue.config.productionTip = false
function embedContent(elementId) {
let contents = ['I am a test', 'nothing', 'connecting', 'bla bla ...', 'Puss in boots', 'Snow White']
document.getElementById(elementId).innerHTML = '<p>' + contents[Math.floor(Math.random()*contents.length)] + '</p>'
}
Vue.component('twitch', {
template: `<div class="video">
<h2>{{name}}</h2>
<div :id="twitchId"></div>
</div>`,
props: ['name'],
data() {
return {
twitchId: ''
}
},
created: function () {
this.twitchId = Date.now().toString(16)
},
mounted: function () {
embedContent(this.twitchId)
}
})
app = new Vue({
el: "#app",
data: {
videos: [
'channel 1',
'World Cup for Football',
'StackOverFlow'
]
}
})
.video {
border: 1px solid red;
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<div>
<twitch v-for="(item, index) in videos" :name="item" :key="index"></twitch>
</div>
</div>

Dojo TabContainer doesn't get formatted correctly until after I do an Inspect Element

I have a Dojo DataGrid with a few rows of data. When I click on a row, I have a TabContainer created in another <div>. Here's what it ends up looking like:
The formatting for the TabContainer is incorrect. However, after I do an "Inspect Element", the formatting corrects itself:
However, the Submit button disappears after the formatting is corrected.
Here's the code I use to create the DataGrid and TabContainer:
<div id="r_body">
<div id="r_list">
</div>
<div id="r_form">
<div data-dojo-type="dijit/form/Form" id="parameters_form" data-dojo-id="parameters_form" encType="multipart/form-data" action="" method="">
{% csrf_token %}
<div>
<div id="r_tab_container"></div>
</div>
<div>
<p></p>
<button id="submit_parameters" dojoType="dijit/form/Button" type="submit" name="submitButton" value="Submit">
Submit
</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
require([
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane",
"dojox/grid/DataGrid" ,
"dojo/data/ItemFileWriteStore" ,
"dojo/dom",
"dojo/domReady!"
], function(BorderContainer, ContentPane, DataGrid, ItemFileWriteStore, dom){
// create a BorderContainer as the top widget in the hierarchy
var bc = new BorderContainer({
style: "height: 500px; width: 230px;"
}, "r_list");
/*set up data store*/
var data = {
identifier: "id",
items: []
};
data.items.push({ id: 'some_id', description: 'some_description',
var store = new ItemFileWriteStore({data: data});
/*set up layout*/
var layout = [[
{'name': 'Title', 'field': 'description', 'width': '200px', 'noresize': true}
]];
/*create a new grid*/
var r_list_grid = new DataGrid({
region: "left",
id: 'r_list_grid',
store: store,
structure: layout,
rowSelector: '0px'
});
bc.addChild(rt_list_grid);
bc.startup();
list_grid.on("RowClick", gridRowClick);
function gridRowClick(evt){
var idx = evt.rowIndex;
var rowData = list_grid.getItem(idx);
var r_url = rowData['url'][0];
var r_id = rowData['id'][0]
require(["dojo/dom", "dojo/request/xhr", "dojo/dom-form", "dijit/layout/TabContainer", "dijit/layout/ContentPane", "dojo/ready", "dojo/domReady!"],
function(dom, xhr, domForm, TabContainer, ContentPane, ready){
var url = window.location.pathname + "dev/" + r_id + "/" + r_url + "/";
xhr(url, {
method: "get"
}).then(
function(response){
var json_response = JSON.parse(response);
var fields_dict = json_response['fields_dict'];
var tc = new TabContainer({
style: "height: 100%; width: 100%;"
}, "r_tab_container");
for(var key in fields_dict) {
var content_string = '';
var fields = fields_dict[key];
for(var field in fields) content_string += '<div>' + field + '</div>';
var tcp = new ContentPane({
title: key,
content: content_string
});
tc.addChild(tcp);
}
tc.startup();
},
function(error){
//Error stuff
}
);
});
}
});
</script>
So what's going here and how do I fix the TabContainer formatting? Thanks!
I had to do a tc.resize(); after I do the tc.startup();

Looking up a specific widget by its id in the Dojo Toolkit

I am developing a mobile application with the Dojo Toolkit. I have the following widget:
define("js/custom/CustomHeading", [ "dojo/_base/declare", "dojo/dom-construct",
"dojo/dom-class", "dojox/mobile/Heading", "dojox/mobile/ToolBarButton",
"dojo/ready" ], function(declare, domConstruct, domClass, Heading,
ToolBarButton, ready) {
return declare("js.custom.CustomHeading", [ Heading ], {
buildRendering : function() {
this.inherited(arguments);
navigationButton = new dojox.mobile.ToolBarButton({
icon : "js/custom/images/navigation.png"
});
navigationButton.placeAt(this.domNode);
ready(function() {
console.log("I entered the block.");
});
}
});
});
If I try to find a widget that is in my html using dijit.byId(), I get no successful result. Dojo can not find the widget, whereas it is there. The widget I want to find looks as follows:
<div id="navigationOverlay" data-dojo-type="dojox.mobile.Overlay">
<ul data-dojo-type="dojox.mobile.RoundRectList">
<li data-dojo-type="dojox.mobile.ListItem"
data-dojo-props="moveTo:'dataServerRuntime',transition:'slide',label:'Health Summary'"
onclick="hideNavigation();"></li>
</ul>
</div>
What am I doing wrong? How can I find the widget?
Use dojo/ready:
ready(function() {
var navigationWidget = reqistry.byId("navigationOverlay");
})
An example at jsFiddle: http://jsfiddle.net/phusick/tgU2x/

Extend Dijit.Dialog with template [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I want to create a Property Sheet like one given below by extending Dijit.Dialog with a template. How can this be achieved?
You can extend it using dojo.declare. You can then override the templateString.
dojo.declare('PropertySheetDialog', [dijit.Dialog], {
//this is the default template for dijit.Dialog
templateString: dojo.cache("dijit", "templates/Dialog.html"),
});
the default template referenced above is dojo/dijit/templates/Dialog.html
you can start with that.
Picture in your question is quite funny...
I extend Dijit.Dialog like this:
Dialog mixed with TemplatedMixin and WidgetsInTemplateMixin, can insert any declarative widgets.
define([
"dojo/_base/declare",
"dijit/Dialog",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dojo/text!./templates/custom.html",
"dojox/form/CheckedMultiSelect"
], function (declare, Dialog, TemplatedMixin, _WidgetsInTemplateMixin, template) {
return declare("app.management.panels.customColumn", [Dialog, TemplatedMixin, _WidgetsInTemplateMixin], {
templateString:template,
}
});
});
./templates/custom.html is a copy of the original templates. put your code in containerNode.
<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"
role="header" level="1"></span>
<span style="display: none;" 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>
<div data-dojo-attach-point="containerNode" class="dijitDialogPaneContent">
<select multiple="true" name="multiselect" data-dojo-type="dojox.form.CheckedMultiSelect">
<option value="VA" selected="selected">Virginia</option>
<option value="WA" selected="selected">Washington</option>
<option value="FL">Florida</option>
<option value="CA">California</option>
</select>
</div>
</div>
Update
Another way to do this, only tested under dojo 1.8.
You can use "dijit/ProgressBar" in ./templates/progressInfo.html
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojox/widget/Standby",
"dijit/TitlePane",
"dijit/_WidgetsInTemplateMixin",
"dojo/text!./templates/progressInfo.html",
"dijit/ProgressBar"
], function (declare, lang, Standby, TitlePane, _WidgetsInTemplateMixin, template) {
return declare("app.management.panel.cpanel.progressInfo", [TitlePane, _WidgetsInTemplateMixin], {
'class':'cpanelProgressInfo',
title:"progressInfo",
toggleable:false,
style:"width:450px;",
mainStore:null,
content:template,
postCreate:function () {
this.inherited(arguments);
this.Standby = new Standby({target:this.domNode, zIndex:1000, color:"#eeeeee"});
this.addChild(this.Standby);
this.Standby.show();
},
refresh:function () {
// my custom dojo store
var rt = this.mainStore.query()[0];
this.set('content', lang.replace(template, rt));
}
});
});
You can create an anonymous widget in the constructor and load a template into that.
However, this can cause problems with layout widgets, and you cannot use data-dojo-attach-event in the template (instead wire up buttons, etc. manually).
define( [ 'dojo/_base/declare',
'dijit/Dialog',
// used for anonymous content widget
'dijit/_WidgetBase',
'dijit/_TemplatedMixin',
'dijit/_WidgetsInTemplateMixin',
'dojo/text!/js/myProject/CustomDialog/templates/CustomDialog.html',
// for wiring up buttons
'dojo/_base/lang',
'dojo/on',
// used in anonymous widget's template
'dijit/form/ValidationTextBox',
'dijit/form/NumberSpinner',
'dijit/form/Textarea',
'dijit/form/Button' ],
function( declare, Dialog, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template, lang, on )
{
return declare( [ Dialog ], // inherit from dijit/Dialog
{
id: 'my_custom_dialog',
title: 'I Am Custom!',
declaredClass: 'myProject.CustomDialog',
constructor: function( myProjectsettings )
{
var contentWidget = new ( declare( [ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ],
{
templateString: template
} ) );
contentWidget.startup();
this.content = contentWidget;
},
postCreate: function()
{
// run any parent postCreate processes
this.inherited( arguments );
// automatically wire up the cancel button
on.once( this.content.cancelButton, 'click', lang.hitch( this,
function()
{
this.onCancel(); // use same method as X button
} ) );
}
} ); // end declare
}
);
se the buildRendering to alter the templateString, thus you get all the _widget goodies from both templates. For more details see the answers in here
Using inner class is simple and will be fully supported by dojo.
define("sample/dialog/CreateUserDialog", [
"dojo/_base/declare",
"dijit/Dialog",
"dojo/text!./resources/CreateUserDialog.html",
"dijit/layout/ContentPane",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin"
], function(declare, Dialog, template, ContentPane, TemplatedMixin, WidgetsInTemplateMixin) {
declare("sample.layout._CreateUserPane", [ContentPane, TemplatedMixin, WidgetsInTemplateMixin],{
templateString: template
});
return declare("sample.dialog.CreateUserDialog", [Dialog],{
title: "Create User",
content: new sample.layout._CreateUserPane()
});
});
You can touch content object by "(Dialog instance).content".