Ext JS: Elements in Combo are not visible, but loaded - ajax

Ext JS 6.2.x is used. A combo is created. It uses ajax proxy request:
Request .../rest/maps/tree?_dc=1519213286176&page=1&start=0&limit=25
Request Method:GET
Status Code:200 OK
Accept:*/*
Accept-Encoding:gzip, deflate, br
Response headers:
Cache-Control:no-cache, no-store, must-revalidate
Connection:keep-alive
Content-Type:application/json
In response body a set of years is returned:
["2015","2017","2018","2019","2016","2020"]
Here is a code:
Ext.define('MapsYears', {
// extend: 'Ext.data.ArrayStore',
extend: 'Ext.data.Store',
alias: 'store.maps-years',
autoLoad: true,
fields: ['year'],
proxy: {
type: 'ajax',
url: 'rest/maps/tree'
}
});
Ext.define('Main.panel.SnapshotNow', {
xtype: 'snapshotNow',
extend: 'Ext.panel.Panel',
requires: [
],
items: [{
id: 'SnapshotNow',
xtype: "combobox",
store: {
type: 'maps-years'
},
displayField: 'year',
valueField: 'year'
}]
});
Items are loaded, I can even click on the combo, and the item appears as a chosen, but a list of items is not visible:
What do I miss?
UPDATE: In a response, it is not actually a json-format. I can fix this issue by changing rest service and returning a correct json. The question is, is there a way to tell ExtJS to process correctly list of elements in the original example, that looks like:
["2015","2017","2018","2019","2016","2020"]

This should fix your data structure
Ext.define('MapsYears', {
extend: 'Ext.data.Store',
alias: 'store.maps-years',
autoLoad: true,
fields: ['year'],
proxy: {
type: 'ajax',
url: 'rest/maps/tree',
reader: {
type: 'json',
transform: data => data.map(year => ({year}))
}
}
});

Related

How to sync my Store when I update the bounded record using form (onUpdateClick). I'm using Extjs 7.5 (Sencha CMD)

This is my first time using a javascript framework, I would like to implement MVVM in my EXT JS application and the data is coming from my WEB API (ASP.NET FRAMEWORK).
My problem is that, I don't seem to understand how to fully use viewModel which looks up to my store. I successfully bound my ViewModel in my grid but now I don't know how to update the selected record using a form (modal) and sync my store (send update request through API)
I have a feeling that I'm doing it the wrong way. I don't know how to do this in fiddle so I'll just paste my code here.
Genre.js [Model]
Ext.define('VAM2.model.Genre', {
extend: 'VAM2.model.Base',
alias: 'model.genre',
fields: [
{name: 'GenreId', type: 'int'},
{name: 'Code', type: 'string'},
{name: 'CreatedBy', type: 'string'},
]
});
Genre.js [Store]
Ext.define('VAM2.store.Genre', {
extend: 'Ext.data.Store',
alias: 'store.genre',
model: 'VAM2.model.Genre',
autoLoad: false,
pageSize: 10,
storeId: 'GenreId',
proxy : {
type : 'rest',
actionMethods : {
read : 'GET'
},
cors:true,
url: 'https://localhost:44332/api/Genre/GetGenresExtJs',
api:{
create: 'https://localhost:44332/api/Genre/CreateGenreExtJS',
read: 'https://localhost:44332/api/Genre/GetGenresExtJs',
update: 'https://localhost:44332/api/Genre/EditGenreExtJS',
destroy: 'https://localhost:44332/api/Genre/CreateGenreExtJS'
},
useDefaultXhrHeader: false,
reader: {
type : 'json',
headers: { 'Accept': 'application/json' },
allDataOptions: {
associated: true,
persist: true
},
rootProperty : 'data',
totalProperty: 'total'
},
}
});
GenreViewModel.js - I'm not sure if this is okay but the read is working
Ext.define('VAM2.view.genre.GenreViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.genre',
requires:[
'VAM2.model.Genre'
],
stores: {
myGenres : {
model: 'VAM2.model.Genre',
autoLoad: true,
proxy : {
type : 'rest',
actionMethods : {
read : 'GET'
},
cors:true,
url: 'https://localhost:44332/api/Genre/GetGenresExtJs',
api:{
create: 'https://localhost:44332/api/Genre/CreateGenreExtJS',
read: 'https://localhost:44332/api/Genre/GetGenresExtJs',
update: 'https://localhost:44332/api/Genre/EditGenreExtJS',
destroy: 'https://localhost:44332/api/Genre/CreateGenreExtJS'
},
useDefaultXhrHeader: false,
reader: {
type : 'json',
headers: { 'Accept': 'application/json' },
allDataOptions: {
associated: true,
persist: true
},
rootProperty : 'data',
totalProperty: 'total'
},
}
}
},
data:{
title:'Sample Binding'
},
formulas: {
currentRecord: {
bind: {
bindTo: '{groupGrid.selection}', //--> reference configurated
//--> on the grid view (reference: groupGrid)
deep: true
},
get: function(record) {
return record;
},
set: function(record) {
if (!record.isModel) {
record = this.get('records').getById(record);
}
this.set('currentRecord', record);
}
}
}
});
View -- This is where it gets confusing. I don't know how to put the bounded data from grid to a form modal and then save and sync my store.
Ext.define('VAM2.view.genre.GenreList', {
extend: 'Ext.container.Container',
xtype: 'myGenreList',
requires: [
'VAM2.view.genre.GenreController',
'VAM2.view.genre.GenreViewModel',
'Ext.grid.column.Boolean',
'Ext.form.field.Checkbox',
'Ext.form.field.TextArea',
'Ext.form.field.Text'
],
controller: "genre",
viewModel: {
type: "genre"
},
width:'100%',
layout: {
type: 'vbox',
pack: 'start',
align: 'stretch'
},
style: {
backgroundColor: '#f5f5f5'
},
items: [{
xtype: 'grid',
reference: 'groupGrid', //--> used in the viewmodel,
bind: {
title: '{title}',
store: '{myGenres}'
},
columns: [{
text:'GenreIdField',
id:'GenreIdField',
dataIndex:'GenreId',
hidden:true
},{
text: 'Code',
dataIndex: 'Code',
flex:1
}, {
text: 'Created By',
dataIndex: 'CreatedBy',
flex: 1
}],
listeners:{
select:'onGenreSelected_FORMA' //--> I'm thinking this will trigger
//-> a form (modal) containing the data to update
}
}]
});
A fiddle example would be great! Thank you!
Screenshot:
This is where I would like to display form modal that can sync/update my store when I modify some data.
To do store.sync() you need to set values on the record first.
Example is without ViewModel:
https://fiddle.sencha.com/#fiddle/3isg&view/editor
select: function (grid, record) {
console.log(record);
let win = Ext.create("Ext.window.Window", {
title: 'Edit',
modal: true,
autoShow: true,
width: 400,
height: 500,
controller: {},
items: [{
xtype: 'form',
reference: 'form',
fieldLabel: 'name',
items: [{
xtype: 'textfield',
name: 'name'
}]
}],
buttons: [{
text: 'cancel',
handler: function () {
win.close();
}
}, {
text: 'save',
handler: function () {
var values = this.lookupController().lookup('form').getValues();
record.set(values);
grid.getStore().sync({
scope: this,
success: function () {
win.close();
Ext.toast({
html: 'Well done',
align: 't'
});
},
failure: function () {
Ext.toast({
html: 'Problem occurred',
align: 't'
});
}
});
}
}],
listeners: {
afterrender: function () {
this.lookupController().lookup('form').loadRecord(record);
}
}
})
}

Extjs proxy just post dirty fields to server, not all filelds

I have a model:
Ext.define('CrudTest.model.User', {
extend: 'Ext.data.Model',
idProperty: 'Id',
fields: [
{ name: 'Id', type: 'int' },
{ name: 'Name', type: 'string' },
{ name: 'PhoneNumber', type: 'int' },
{ name: 'Address', type: 'string' },
{ name: 'StateId', type: 'int', reference: 'State' },
],
validators: [
{ type: 'presence', field: 'Name', message: 'define name, please' },
{ type: 'length', field: 'PhoneNumber', max: 8, messsage: 'lower than 8 digit' },
],
proxy: {
type: 'ajax',
api: {
create: 'home/new',
read: 'home/users',
update: 'home/Edit',
destroy: 'home/Delete'
},
},
});
and a form that load data to form by loadRecord() and my handler code for submit button is:
var form = this.up('form').getForm();
if (form.isValid()) {
form.getRecord().save();
}
it make a post request through my proxy model good. but the body of request just have dirty(edited) fields. why i don't have other fields?
but in request body i have just dirty fields. why? i know updateRecord() uses getFieldValues([onlyDirty=false]), how can send all fields values?
I use extjs 5
Finally find the problem. Ext.data.writer.Writer has a config property writeAllFields
So i change the proxy to this:
proxy: {
writer:{ writeAllFields:true },
type: 'ajax', //also works with type: 'direct',
api: {
create: 'home/new',
read: 'home/users',
update: 'home/Edit',
destroy: 'home/Delete'
},
You can set crtical: true on the Model to any fields you always want written whether changed or not, e.g.
{ name: 'title', type: 'string', critical: true }

Sencha Touch 2 proxy not firing any requests

I'm trying to just get a list loaded from a proxy that uses rest to get data from the server. I can't figure out what I'm doing wrong, but I don't see any GET requests to /restaurants in Chrome's network call log. Originally I thought maybe the controller wasn't being included, but it's all there and when I add data in the store it populates. This isn't throwing any errors, so I can't debug it. I've gone through every possible tutorial I could find as well as the documentation. Any help or insight is greatly appreciated.
Controller:
Ext.define('Appetize.controller.Restaurants', {
extend: 'Ext.app.Controller',
config: {
models: ['Restaurant'],
views: [
'RestaurantList',
],
refs: {
},
control: { }
}
}
Model:
Ext.define('Appetize.model.Restaurant', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'id'},
{name: 'name'},
{name: 'delivers'},
{name: 'active'}
]
}
});
store:
Ext.define('Appetize.store.Restaurants', {
extend: 'Ext.data.Store',
requires: ['Appetize.model.Restaurant'],
config: {
model: 'Appetize.model.Restaurant',
proxy: {
type: 'rest',
url: '/restaurants',
autoLoad: 'true'
}
}
});
View:
Ext.define('Appetize.view.RestaurantList', {
extend: 'Ext.List',
xtype: 'restaurantListCard',
config: {
iconCls: 'home',
title: 'Restaurants',
id: 'restaurantList',
store: 'Restaurants',
onItemDisclosure: true,
itemTpl: '{name}'
}
});
It turns out I had autoLoad in the wrong place. It shouldn't be within the proxy settings. Instead it should be outside the proxy as part of config.
Ext.define('Appetize.store.Restaurants', {
extend: 'Ext.data.Store',
requires: ['Appetize.model.Restaurant'],
config: {
model: 'Appetize.model.Restaurant',
proxy: {
type: 'rest',
url: '/restaurants',
},
autoLoad: 'true'
}
});

Sencha Touch 2 rendering store data to panel

I am reading data from a JSON feed through a Store. My problem is I am unable to display the data in a View-Panel.
My panel code is as follows:
Ext.define('Layouts.view.Node', {
extend: 'Ext.Panel',
xtype: 'node',
config: {
title: 'Node Data',
styleHtmlContent: true,
scrollable: 'vertical',
tpl: new Ext.XTemplate(
'<div>TITLE: {title}</div>'
),
},
});
The Store code is as follows:
Ext.define('Layouts.store.Node', {
extend: 'Ext.data.Store',
config: {
storeId: 'Node',
autoLoad: true,
model: 'Layouts.model.Node',
proxy: {
type: 'ajax',
url: 'http://178.79.128.76/revivaltimes/app/content/0',
reader: {
type: 'json',
rootProperty: 'JSON',
}
},
},//config
});
And the model code follows:
Ext.define('Layouts.model.Node', {
extend: 'Ext.data.Model',
config: {
fields: [
'title',
'body',
]
},
});
I don't know why my view comes up blank.
Take a look at the DataView component: http://docs.sencha.com/touch/2.3.1/#!/api/Ext.dataview.DataView
The DataView is the proper way to render data from a store. Your view would become something like that (untested code):
Ext.define('Layouts.view.Node', {
extend: 'Ext.dataview.DataView',
xtype: 'node',
config: {
title: 'Node Data',
styleHtmlContent: true,
scrollable: 'vertical',
store: 'Node',
itemTpl: new Ext.XTemplate(
'<div>TITLE: {title}</div>'
),
},
});
Note the use of itemTpl for specifying the item template.

Appending to list not updating on pull to refresh

I am still new to ST so I am probably doing several things wrong here but I can't figure out where the problems are.
Problem 1
when I use the pull to refresh plug-in, I get double the data instead of it just refreshing the data. I have seen to use a propertyId and so I did to no avail. This should be simple so probably something silly I'm doing wrong.
Problem 2
I am trying to figure out the most efficient way to use the MVC architecture and I have read through the documentation and many examples. So, I don't know if I am just not understanding clearly or need a better example. I am trying to create a simple app for now with a list that I can tap on an item and get a detailed view of that item. I will later evolve it into a more robust monster but for now I am trying to understand the basics. I finally got my close button to close the detail view when I click a list item but then I can no longer get a detail view when tapping another item. I have read that this is due to 'autoDestroy: off' not being present but I tried that, also with no luck. I want to be able to create certain buttons like 'close' that I can put in multiple views and just have to have the logic in the controllers.
Main View
Ext.define('SenchaFirstApp.view.DistributorView', {
// extend: 'Ext.form.Panel',
extend: 'Ext.Container',
requires: ['SenchaFirstApp.store.DistributorStore', 'Ext.dataview.List', 'Ext.Toolbar', 'Ext.form.Panel'],
model: 'SenchaFirstApp.model.Distributors',
alias: 'widget.mainlist',
xtype: 'mainlist',
config:
{
layout: 'fit',
border: 5,
title: 'Distributors',
html: 'My datalist',
autoDestroy: false,
items:[{
xtype: 'toolbar',
docked: 'top',
title: 'Distributor List',
height: 40,
centered: true,
items: [
{
xtype: 'button',
text: 'Close',
width: 100,
height: 20,
name: 'close',
// iconCls: 'delete',
}]
},
{
autoLoad: true,
html: ['<div class="distr"><table><tr><th>Type</th><th>Distributor</th><th>Site</th><th>Status</th><th>Active</th><th>Assigned</th><th>State </th><th>Schedule</th><th>Finished</th></tr></table></div>'],
itemTpl: [ '<div class="distr"><table><tr><td>{t}</td><td>{distr}</td><td colspan="2">{site}</td><td>{status}</td> <td>{active}</td><td>{assigned}</td> <td>{state}</td><td>{schedule}</td><td>{finished}</td></tr></table></div>' ],
xtype: 'list',
store: 'DistrID',
plugins: [
{
xclass: 'Ext.plugin.PullRefresh',
pullRefreshText: 'Pull down to refresh Distributor List'
}],
ui: 'showDetails',
id: 'mainlist',
autoDestroy: false,
}
]
},
});
Detailed View
Ext.define('SenchaFirstApp.view.DetailView',{
extend: 'Ext.Panel',
requires: ['Ext.Toolbar'],
model: 'SenchaFirstApp.model.Distributors',
alias: 'widget.detailview',
xtype: 'detailview',
name: 'detail',
config:{
html: 'This will contain detailed information',
xtype: 'panel',
// fullscreen: false,
centered: true,
modal: false,
scrollable: true,
width: 300,
height: 200,
},
});
Store
Ext.define('SenchaFirstApp.store.DistributorStore', {
extend: 'Ext.data.Store',
requires: ['SenchaFirstApp.model.Distributors'],
config: {
// xtype: 'distrlist',
storeId: 'DistrID',
model: 'SenchaFirstApp.model.Distributors',
autoLoad: true,
proxy: {
type: 'jsonp',
url:'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://gdata.youtube.com/feeds/api/users/hobbitin5/uploads&num=4',
reader: {
type: 'json',
rootProperty: 'responseData.feed.entries'
}
}
}
Controller to get detailed view
Ext.define('SenchaFirstApp.controller.DistributorsController',{
extend: 'Ext.app.Controller',
config:
{
refs:
{
mainlist: '#mainlist',
},
control:
{
mainlist: {
itemtap: 'dispDetail'
},
},
//when item is tapped
listeners: {
itemtap: function(list, index, items, record)
{
console.log('An item was tapped and the listener heard it');
}
}
},
dispDetail: function(view, record) {
console.log('Item was tapped on the Data View');
var oldView = this.getMainlist();
var curRecord = oldView.getStore(record);
var newView = Ext.create('SenchaFirstApp.view.DetailView');
console.log(curRecord);
curRecord += 'other stuff';
newView.setHtml(curRecord);
newView.add(
{
xtype: 'toolbar',
docked: 'top',
title: 'Details',
height: 40,
items: [
{
xtype: 'button',
text: 'Close',
width: 100,
height: 20,
name: 'close',
}]
}
)
oldView.add(newView);
// Ext.Viewport.add(newView)
// Ext.Viewport.setActiveItem(newView)
}
});
Controller for buttons (just close for now)
Ext.define('SenchaFirstApp.controller.NavController', {
extend: 'Ext.app.Controller',
config:
{
refs:
{
mainlist: 'mainlist',
main: '#mainlist',
closeBtn: 'button[name=close]',
detaillist: {
selector: 'panel panel[name=detail] deetaillist',
xtype: 'detailview',
}
},
control:
{
closeBtn: {
tap: 'closeView',
},
mainlist: {
tap: 'closeView',
},
detaillist: {
tap: 'closeView',
}
}
},
closeView: function(){
var newView = this.getMainlist();
// var child = Ext.Viewport.getActiveItem();
var child = this.getDetaillist();
var instance = Ext.getCmp('mainlist');
var activeIndex = instance.indexOf(instance.getActiveItem());
var curIndex = activeIndex+1;
var closeView = this.getDetaillist();
console.log('Close btn clicked' + ' child: ' + this.child + ' activeIndex: ' + activeIndex);
// Ext.Viewport.destroy(closeView); //(child);
newView.remove(child);
newView.destroy();
Ext.Viewport.add(Ext.create('SenchaFirstApp.view.DistributorView'));
` }
})`;
Model
Ext.define('SenchaFirstApp.model.Distributors', {
extend: 'Ext.data.Model',
config: {
idProperty: 'DistrID',
fields: [
{name: 'DistrID'},
{name: 't', type: 'string'},
{name: 'distr', type: 'string'},
{name: 'group', type: 'string'},
{name: 'site', type: 'string'},
{name: 'status', type: 'string'},
{name: 'active', type: 'string'},
{name: 'assigned', type: 'string'},
{name: 'state', type: 'string'},
{name: 'schedule', type: 'string'},
{name: 'finished', type: 'string'},
//{mapping: 't',
// name: 'DistrID'}
],
}
});
I understand that is a lot but any help is appreciated...even a nudge in the right direction. Thanks in advance! Also, I'm sure there is stuff in there that doesn't need to be as I've had trouble locating good examples for what I am trying to accomplish so I have pieces here and there from different examples that I've tried to get to play nice together :(
I solved the refresh issue by changing the idProperty to 'id' and put that in my model field list. I'm still not sure why the 'DistrID wasn't working but I had an 'id' field in my script that held the server response that I didn't know about as I didn't write that part. So, I would have to guess that is why it wasn't working.
I had read that 'autoDestroy: false' is what was needed to allow clicking a second time but that was wrong. When I took that property out it allowed me to continue to open and close details of list items.
Now I just have to work on passing id's of list items clicked to get a detailed view of that particular item. If anyone can help with that it would be great or I will post a new question. Thanks!
I figured out how to get the list item id in case it can help anyone...
Iny my DistributorController I simply get the store and the record id
var store = Ext.getStore('NodeStore');
var id = record.get('id');
Then set the params and load the store
store.getProxy().setExtraParams({id: id});
store.load();
I did also find that you can't reference your store through the controller with refs. Instead get the store as I did above with var store = Ext.getStore('StoreName');
This is all pretty simple stuff but I'm still very knew so maybe it can help out another n00b

Resources