How can I create dojo combobox dropdown - javascript

I created dojo div element for a dojo combo box . Now I want to create a tree like structure to choose drop down value. I want to attach tree object in div element through java script file using read or write store (dojo/data/ItemFileReadStore).....
I am trying the below html and js files for it but I am getting the below error message. no such method dom.byId
div element for combo box :
<div>
<tr>
<td><label for="fixedSubCategory">Fixed SubCategory</label></td>
<td><select data-dojo-type="dijit/form/ComboBox"
id="fixedSubCategory" name="fixedSubCategory" value="">
</select></td>
</tr>
JS file to attach tree object :
var displayData ={
"identifier":"id",
"label":"name",
"items":[
{
"type": "parent",
"name": "Countries",
"id": "countries",
"children":[
{"type":"Leaf", "name":"Country 1", "id":"country1"},
{"type":"Leaf", "name":"Country 2", "id":"country2"},
{"type":"Leaf", "name":"Country 3", "id":"country3"},
{"type":"Leaf", "name":"Country 4", "id":"country4"},
{"type":"Leaf", "name":"Country 5", "id":"country5"},
{"type":"Leaf", "name":"Country 6", "id":"country6"}
]
}]}
var store1 = new dojo.data.ItemFileReadStore({ data: displayData });
var treeModel = new dijit.tree.ForestStoreModel({
store: store1,
query: {"type": "parent"},
rootId: "root",
rootLabel: "Groups",
childrenAttrs: ["children"]
});
var treeObject = new dijit.Tree({
model: treeModel
}, "treeDiv")
if (dijit.byId("fixedSubCategory") != null) {
dom.byId("fixedSubCategory").appendChild(treeObject.domNode);
treeObject.startup();
}

Typically, dom.byId() and such is seen in the context of a proper AMD module, e.g.:
define([ 'dojo/dom', ... ], function (dom, ...) {
// do something with dom.byId
});
If you are writing modules in AMD format (which is heavily encouraged), make sure you are actually including the dojo/dom module in your dependencies list and assigning the module to the dom argument in your factory function (if you think you are already doing this, then make sure the dependencies array and function argument order match up). Then it should work fine.
(Also, the appropriate way to reference dijit.byId would be via the dijit/registry module, rather than the dijit global.)
On the other hand, it looks like most of your other code isn't really making use of the AMD format at all (e.g. dojo.data, dijit.tree, etc.). While it'd be recommended to update to the AMD format (and it seemed like you had been using it in Populating ComboBox dynamically in dojo with domAttr), the non-AMD, global equivalent to dom.byId is dojo.byId.

The easiest way is to use a combobox, i guess.
We managed it like this :
"results" is the result of a query on our street-shape-file.
function streetsToCombobox(results){
var adress;
var values = [];
var testVals={};
var features = results.features;
require(["dojo/_base/array","dojo/store/Memory","dijit/form/ComboBox"],
function(array,Memory,Combobox){
if (!features[0]) {
alert(noDataFound);
}
else {
array.forEach(features, function(feature, i){
adress = feature.attributes.STRASSE;
//Check for doublefeatures
if (!testVals[adress]) {
testVals[adress] = true;
values.push({
name: adress
});
}
});
values.sort(SortByName);
var dataItems = {
identifier: 'name',
label: 'name',
items: values
};
storeStreet = new Memory({
data: dataItems
});
}
var comboBox = new ComboBox({
id: "MyCB",
name: "street",
value: "",
store: storeStreet ,
searchAttr: "name"
},"DomeNodeForBox");
});
}
For all further Infos have a close look into the Documentation : http://dojotoolkit.org/reference-guide/1.10/dijit/form/ComboBox.html#dijit-form-combobox

Related

SAPUI5: Routing with parameters - How get correct path of binding context

I am trying to implement routing with parameters as in this walkthrough: https://sapui5.hana.ondemand.com/1.58.7/#/topic/2366345a94f64ec1a80f9d9ce50a59ef
However, instead of getting data as a path
/Invoices(CustomerName='Alfreds%20Futterkiste',Discount=0f,OrderID=10835....
when they do:
oRouter.navTo("detail", {invoicePath:
oItem.getBindingContext("invoice").getPath().substr(1)});
when I use the function in my controller (see onFwdDetail below), I only get a string path:
nodes/0
And this cannot be used in routing (see manifest.json below):
Invalid value "nodes/0" for segment "{detailPath}".
I am assuming it is because my JSON file is structured differently than in the walkthrough. How do I get the correct path with data for routing?
The relevant section of my implementation are as follows:
Data.JSON
{
"nodes": [
{
"text": "Text1",
"status1": "Status10",
"status2". "Status11"
},
{
"text": "Text2",
"status1": "Status20",
"status2". "Status21"
},...]
}
Overview.view.xml
<Table
items="{path: 'mydata>/nodes'}">
...
<ColumnListItem type="Navigation" press="onFwdDetail">
Overview.controller.js
onInit : function() {
var oModel = new JSONModel("model/Data.JSON");
this.getView().setModel(oModel, "mydata");
},
onFwdDetail : function(oEvent) {
var oItem = oEvent.getSource();
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("detail", {detailPath:
oItem.getBindingContext("mydata").getPath().substr(1)});
console.log(oItem.getBindingContext("mydata").getPath().substr(1));
}
manifest.json
{
"pattern": "details/{detailPath}",
"name": "details",
"target": "details"
}
Their path is a path to an entity of an OData model. Your path is a path to an entity of a JSON model.
Those paths are built entirely different. Most importantly your path contains a slash, while theirs does not. This confuses the parser which tries to match details/{detailPath} and details/nodes/0.
The 0 itself is a valid path in your example. nodes is an array and it's possible to do nodes[0]. It's just that the routing class doesn't like the format.
So what you can do is simply passing the 0 to your detailPath. In your detail view you can then build the original key ("nodes/" + detailPath) and bind your view to that key.
I would also recommend this approach for OData btw:
extract actual keys from bound object
pass keys to your router
in your detail view build a key from the passed arguments
Pseudo code for an OData model:
Controller A:
// read relevant values from binding context
var oContext = oItem.getBindingContext("myModel");
var sKeyName = oContext.getObject("CustomerName");
var sKeyId = oContext.getObject("OrderID");
// trigger navigation
oRouter.navTo("orderDetail", { name: sKeyName, id: sKeyId });
Controller B:
_onRouteMatched: function (oEvent) {
var oModel = this.getModel("myModel");
var that = this;
// read params from routing
var sKeyName = oEvent.getParameter("arguments").name;
var sKeyId = oEvent.getParameter("arguments").id;
// as soon as the metadata of the model are available there is a great API to build keys
oModel.metadataLoaded().then(function () {
var sPath = oModel.createKey("/Invoices", {
CustomerName: sKeyName,
OrderID: sKeyId
});
// sPath should be something like "/Invoices(CustomerName='Troll',OrderID=12345)"
that.getView().bindElement({ path: sPath });
});
},
manifest.json
"pattern": "order/{name},{id}",
"name": "orderDetail"

Data Model's "serialize" function not called on property "set"ting

Also asked on Sencha's site here
My data model's "serialize" function is not called when I call
model.set("<fieldName>", <newValue>);
Here's a fiddle
I'm pretty unclear on why the serialize function isn't called...am I missing something, or is this a bug?
(And here's the code from the fiddle)
Ext.application({
name : 'Fiddle',
requires: [
"Ext.data.Store"
],
launch : function() {
var store = Ext.create("Ext.data.Store", {
data: [{Id: 0, Name: "Bill", Props: "{foo: 2, bar:{pan:5}}"}],
fields:[
{name: "Id", type: "int"},
{name: "Name", type: "string"},
{name: "Props",
convert: function(value, record){
console.log("called convert");
return Ext.JSON.decode(value);
},
serialize: function(value, record){
alert("never getting called!! :(");
console.log("sure, i'll put log here too..not getting called though");
return Ext.JSON.encode(value);
}
}
]
});
console.log(store.getAt(0));
var rec = store.getAt(0);
var newProp = {rec:"junk", foo: "orange"};
console.log(newProp);
rec.set("Props",newProp);
}
});
Mappings from source content (JSON/XML) to business model (Ext.data.Model) are not automatically created in ExtJS's data model system. As such, another step is needed to produce this relationship using mapping/associationsor something similar.
I.e. The data model doesn't store the original JSON to read/write from, which is fine for most cases. When a JSON string needs to be updated via ExtJS, one solution is to, on the model, set
convertOnSet
to false, allowing for custom manipulation of the JSON string via extract/update functions on the data model.

Backbone Menu Not Sorting

I'm having trouble getting a Backbone collection to sort properly. I inherited the project, so there may be some shenanigans someplace else, but I want to rule out any syntax error on my part.
The project uses a JSON file to handle the data:
"classifications": [
{
"name": "1 Bedroom",
"alias": "1BR",
"id": "1BR",
"menu_desc": "Residences"
},
{
"name": "2 Bedroom",
"alias": "2BR",
"id": "2BR",
"menu_desc": "Residences"
},
{
"name": "3 Bedroom",
"alias": "3BR",
"id": "3BR",
"menu_desc": "Residences"
},
{
"name": "4 Bedroom",
"alias": "4BR",
"id": "4BR",
"menu_desc": "Residences"
},
{
"name": "Common Areas",
"alias": "Common",
"id": "Common",
"menu_desc": "Resident Amenities"
}
]
Previously, there were no one-bedroom units, and the order in which it rendered was this:
I added the one-bedroom classification, and suddenly the order was this:
I did some digging and found documentation about the comparator property, but it only seems to apply to collections. This project doesn't use a collection for the classifications. It does for the submenu items (which floor the units are on, etc.), but not the main menu:
var MenuClassificationListView = Backbone.View.extend({
id: "classification_accordion",
template: _.template( "<% var classifications = this.options.classifications; _.each(this.collection.attributes, function(v,k) { %>"+
"<h3 class='<%= k %>'><%= classifications.get(k).get('name') %>"+
"<p><%=classifications.get(k).get('menu_desc')%></p></h3>"+
"<% var model = new MenuClassificationList(v); var view = new MenuClassificationItemView({collection:model, classification:k}); %>"+
"<% print(view.render().el.outerHTML); %>"+
"<% }); "+
"%>"),
render: function(){
//console.log(this.options.classifications);
//console.log(this.collection.attributes);
//alert(1);
this.$el.html(this.template());
return this;
}
});
How do I incorporate the comparator?
Thanks,
ty
One way could be to define a collection for the classifications, same way they are defined for the other items you mention:
var Classifications = Backbone.Collections.extend({ // etc. etc.
That way you can add the comparator and it will always be sorted.
Another way is to sort (http://underscorejs.org/#sortBy) the array in the initialize function in your view:
initialize: function(options) { // sorry don't remember the exact syntax for the parameters passed in, but I believe options is what you need
this.options.sortedclassifications = _sortBy(options.classifications, function (c) { return parseInt(c.id); }); // or any other sorting logic
}
Then in the template use the sorted classifications:
template: _.template( "<% var classifications = this.options.sortedclassifications; _.each(this.collection.attributes, function(v,k) { %>" + // etc. etc.
This should give you what you need. However, if I may add a personal opinion, I would go through the effort of defining a Collection for the classifications and a model for the single classification. Moreover, I would keep the MenuClassificationListView but also create a MenuClassificationView that will hold the single classification template.
In this way you are able to compose views, change rendering of the single classification without changing the list and scope the events to the inner views (so clicking on a single classification is handled by the single classification view). It makes everything cleaner, more composable and readable, in my opinion.
_.sortBy does not need to be used as Backbone collections already come with built in functionality for sorting.
See: http://backbonejs.org/#Collection-comparator
Example:
var SortedCollection = Backbone.Collection.extend({
comparator: 'key'
});
var mySortedCollection = new SortedCollection([{a:5, key:2}, {key:1}]);
console.log( mySortedCollection.toJSON() );
// [{key:1}, {a:5, key:2}]
However, the collection will not be automatically re-sorted when changing the key attribute. See:
mySortedCollection.at(0).set( 'key', 3 );
console.log( mySortedCollection.toJSON() );
// [{key:3}, {a:5, key:2}]
You have multiple options to solve this problem: you can manually call mySortedCollection.sort() or you can initialize the collection by binding its change:key event to re-sort the collection. The change:key event is triggered by the model whose key attribute is changed. This event is automatically propagated to the collection.
var AutoSortedCollection = Backbone.Collection.extend({
comparator: 'key',
initialize: function() {
this.listenTo( this, 'change:key', this.sort );
}
});
In addition, I suggest removing functionality from the templates. It is easy to debug Backbone Views, but it gets harder to read the stack trace as you move functionality inside the template string. You also enforce proper separation of concerns by using your Backbone View for preparing all data for presentation and your template should just display it.
var MyView = Backbone.View.extend({
//...
serializeData: function() {
return {
classifications: this.collection.toJSON(),
keys: this.collection.length > 0 ? this.collection.at(0).keys() : []
}; // already sorted
}
render: function() {
this.$el.html(this.template( this.serializeData() ));
}
});
Your template string becomes much easier to read: you can directly use the variables classifications and keys, iterate on them with _.each and simply reference to values without having to deal with the Collection syntax.

Accessing variables across different scopes in Javascript & YUI 3

I'm new to YUI 3 and YUI in general. I'm trying to pass data between classes and methods.
In this example I'm using the gallery-sm-treeview plugin to build a file tree. There's a class named TreeView to initialize and render the tree. There's another class named MenuBar where I want to access some of the plugin-specific methods through TreeView's getter method.
However, the variable var treeview inside the YUI().use() scope is of course not accessible from outside. How to do it?
YUI.add('treetool.TreeView', function(Y) {
Y.treetool.TreeView = Class.extend({
init : function(elementId) {
YUI({
gallery: 'gallery-2013.06.20-02-07'}).use('gallery-sm-treeview', function (Y) {
// Create a new TreeView with a few nodes.
var treeview = new Y.TreeView({
// Tell the TreeView where to render itself.
container: elementId,
// Populate the treeview with some tree nodes.
nodes: [
{label: 'Node 1'},
{label: 'Node 2', children: [
{label: 'Child 1'},
]
});
// Render the treeview inside the #treeview element.
treeview.render();
});
},
getSomeData : function () {
return treeview.getSelectedNodes();
}
});
}, '0.0.1', {
requires : [ 'jquery' ]
});
and
YUI.add('treetool.MenuBar', function(Y) {
Y.treetool.MenuBar = Class.extend({
init : function(treeObj) {
var someData = treeObj.getSomeData();
},
});
}, '0.0.1', {
requires : [ 'jquery' ]
});
It might not be the "best" way to do it, but one way would be to define the treeview variable in a scope that is available in both places.
YUI.add('treetool.TreeView', function(Y) {
var treeview;
//...
and
treeview = new Y.TreeView({ // removed "var "

Dynamic Models, Stores, and Views -- Best way to

NOTE: Author is new to EXT JS and is trying to use MVC in his projects
imagine i have a web service whose data model is not fixed. I would want to have my models dynamically created, from which i dynamically create stores and hence dynamic components whose data is in those stores.
Lets start by seeing a sample class definition of a model:
Ext.define('MNESIA.model.User', {
extend: 'Ext.data.Model'
});
In this model definition, i have left out the 'fields' parameter in the config object. This is because whwnever i create an instance of a model of the type above, i want to dynamically give it its fields definition, in other words i can have many instances of this model yet all having different definition of their 'fields' parameter.
From here i create a definition of the store, like this:
Ext.define('MNESIA.store.Users', {
extend: 'Ext.data.Store',
autoLoad: true
}
});
There, i have a store definition. I have left out the 'model' parameter because i will attach it to every instance of this class dynamically. Infact, even the 'data' and 'proxy' settings are not mentioned as i would want to asign them during the instantiation of this store.
From there, i would want to have dynamic views, driven by dynamic stores. Here below i have a definition of a Grid
Ext.define('MNESIA.view.Grid' , {
extend: 'Ext.grid.Panel',
alias : 'widget.mygrid',
width: 700,
height: 500
});
I have left out the following parameters in the Grid specification: 'columns', 'store' and 'title' . This is because i intend to have many Grids created as instances of the specification above yet having dynamic stores, titles and column definitions.
Some where in my controller, i have some code that appears like this:
function() {
var SomeBigConfig = connect2Server();
/*
where:
SomeBigConfig = [
{"model":[
{"fields":
["SurName","FirstName","OtherName"]
}
]
},
{"store":[
{"data":
{"items":[
{"SurName":"Muzaaya","FirstName":"Joshua","OtherName":"Nsubuga"},
{"SurName":"Zziwa","FirstName":"Shamusudeen","OtherName":"Haji"},
...
]
}
},
{"proxy": {
"type": "memory",
"reader": {
"type": "json",
"root": "items"
}
}
}
]
},
{"grid",[
{"title":"Some Dynamic Title From Web Service"},
{"columns": [{
"header": "SurName",
"dataIndex": "SurName",
"flex": 1
},{
"header": "FirstName",
"dataIndex": "FirstName",
"flex": 1
},
{
"header": "OtherName",
"dataIndex": "OtherName",
"flex": 1
}
]}
]
}
]
*/
var TheModel = Ext.create('MNESIA.model.User',{
fields: SomeBigConfig[0].model[0].fields
});
var TheStore = Ext.create('MNESIA.store.Users',{
storeId: 'users',
model: TheModel,
data: SomeBigConfig[1].store[0].data,
proxy: SomeBigConfig[1].store[1].proxy
});
var grid = Ext.create('MNESIA.view.Grid',{
store: TheStore,
title: SomeBigConfig[2].grid[0].title,
columns: SomeBigConfig[2].grid[1].columns
});
// From here i draw the grid anywhere on the, page say by
grid.renderTo = Ext.getBody();
// end function
}
Now this kind of dynamic creating of models, then stores, and then grids does result into memory wastage and so this would require the destroy methods of each component to be called each time we want to destroy that component.
Questions:
Qn 1: Does the MVC implementation of EXT JS 4 permit this ?
Qn 2: How would i gain the same functionality by using the xtypes of my new classes. Say for example:
{
xtype: 'mygrid',
store: TheStore,
title: SomeBigConfig[2].grid[0].title,
columns: SomeBigConfig[2].grid[1].columns
}
Qn 3: If what i have written above really works and is pragmatically correct, can i apply this to all components like Panels, TabPanels, Trees (whereby their Configs are sent by a remote server) ?
Qn 4: If i have Controllers A and B, with controller A having a specification of views: [C, D] and Controller B having views: [E, F], would it be correct if actions generated by view: E are handled by Controller A ? i.e. Can a controller handle actions of a view which is not registered in its views config ?
NOTE: am quite new to Ext JS but would love to learn more. Advise me on how to improve my EXT JS learning curve. Thanks
In my option ,your model must map onto the store that is to be rendered to the view like for example,if implement the model part like this
{"model":[{"fields":[{name:'name',type:'string'},
{name:'id',type:'string'}]}]} ,this will be easily mapped onto the store for the view render it.

Categories

Resources