ExtJS4 - Iterate through Store in Grid - grid

I want to iterate through store and make grid columns dynamically. When I use columns.push method in the onLoad event of Store, I got this error: "headerCtCfg is undefined". This is my code:
Ext.define('App.view.UserList' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.userlist',
store: 'Users',
initComponent: function() {
var store = Ext.getStore( this.store );
store.on('load', function () {
var columns = this.columns = [];
columns.push( {header: 'H', dataIndex: '0'} );
Thank you in Advance

Try to add this.callParent(arguments) before doing anything else in your initComponent function. This way view gets completely created and you will be able to access columns.
Also I suggest to look at reconfigure method of tableview to change store and columns on the fly.
Update: Try to use Ext.apply instead of columns.push:
Ext.apply(this, {
columns: [ list of your columns ]
});
Update2: load() is async. So you might consider creating grid first with dummy column, then load store and replace it with new data.

Related

Improving performance for many Vue components on the same page

I am building an app that mounts hundreds or even thousands of instances of a vue component in the same view. Each component has an id that refers to an object in the vuex store.
<my-component :id="item1"></my-component>
<my-component :id="item2"></my-component>
<my-component :id="item3"></my-component>
...
The store:
state: {
myComponentData: [
{
id: 'item1',
name: 'Hawaiian Shirt',
selected: false,
// ...
},
// ...
]
}
In my-component, I look up its object in the store and store it in a computed property:
computed: {
myComponentData: function () {
return this.$store.state.myComponentData.find(el => el.id === this.id);
},
isSelected: function () {
return this.myComponentData.selected;
},
// ...
}
The object properties in the store can be manipulated by interacting with the component itself or by other components elsewhere in the app.
The problem is when I try running this with several hundred or 1000+ elements, it takes 30 seconds or longer to load.
If I remove the computed properties, or replace them with static values, then the page loads seamlessly. It's only when I try to load all of the computed properties from the store that I have lag issues.
Is there a way to improve performance when loading many (1500+) Vue components that use computed properties and Vuex? I have looked into dynamic/async components, vue-async-computed, and vue-rx as possible solutions, but I'm not sure which would help in this case.
The problem is within the logic. If you have 1000 items, you create 1000 components. Then each of them loops through the list of items in order to find the proper one based on id. So you are basically doing 1000 * 1000 loops (worst case of course). Which is not the worst thing - you are adding a reactivity through this computed property! Every time something changes, the computed method will fire again, leading to another 1000 loop (worst case scenario if your item is the last).
You have a few options:
Get the store's item while setting the data in your component. This will not create a computed property, so you'll be having a static data. Which will lead to making your own personal watchers for all the data you want changed.
(I would go with this) You're having the list of items in the parent component that shows the list. Don't pass just the id - pass the whole item. This way you won't need to use any computed properties, and you will have reactivity out of the box (props gets updated in children automatically).
Just don't add that many loops and computed properties - as the name states, they are for computing, not for filtering something you can filter elsewhere ;)
Good luck!
I think the Array.find() operation is most costly. Having it in the computed property means it runs every time the dependencies change.
You can get the array index in mounted() and use it in the computed,
export default {
name: "MyComponent",
props: ["id"],
data() {
return {
storeIndex: -2
};
},
mounted() {
this.storeIndex = this.$store.state.myComponentData.findIndex(
el => el.id == "item" + this.id
);
},
computed: {
myComponentData: function() {
// return this.$store.state.myComponentData.find(
// el => el.id === "item" + this.id
// );
return this.$store.state.myComponentData[this.storeIndex] || {};
},
isSelected: function() {
return this.myComponentData.selected;
}
}
};
Here is a CodeSandbox with a working example.

Get Dropdown Value in Meteor Js?

I did one sample Searchapp using meteor add sebdah:autocompletion package.When ever given inputs it shows drop down list.In this list how to get selected value as shown below code:
Js Code :
Friends = new Meteor.Collection('friends');
if (Meteor.isClient) {
/**
* Template - search
*/
Template.search.rendered = function () {
AutoCompletion.enableLogging = true;
var res = AutoCompletion.init("input#searchBox");
console.log("res :"+res);
}
Template.search.events = {
'keyup input#searchBox': function (e,t) {
AutoCompletion.autocomplete({
element: 'input#searchBox', // DOM identifier for the element
collection: Friends, // MeteorJS collection object
field: 'name', // Document field name to search for
limit: 0, // Max number of elements to show
sort: {name: 1}
});
}
}
}
I didn't get any idea about this.So please suggest me how to get selected drop down list values?
AutoCompletion package doesn't give any good API to read value on select. Instead you need to manually read the value of input#searchBox.
Please take a look at source code.
I would recommend to implement searching in your meteor app using Arunoda's approach : https://meteorhacks.com/implementing-an-instant-search-solution-with-meteor.html

How do i use a JsonRestStore with a search form and editable DataGrid

I am trying to implement a search form where the results would be displayed via a dojo 1.6 data grid. I have the rendering working, I make an ajax call on form submit and then build a Datagrid in the call back function using the ItemFileWriteStore.
function search()
{
var action = './search.json';
dojo.xhrPost({url: action, form:"searchForm",
load: function(result) {
var newStore = new dojo.data.ItemFileWriteStore({
data: {
identifier: "id",
items: JSON.parse(result),
url:'./search.json'
}
});
var grid = dijit.byId("searchResultsGrid");
if(grid == null) {
var layout = [[
{'name': 'Id', 'field': 'id', 'width': '50px'},
{'name': 'Name', 'field': 'name', 'width': '50px',editable: true,},
{'name': 'Source', 'field': 'source', 'width': '50px',editable: true,},
{'name': 'Version', 'field': 'version', 'width': '50px',editable: true,}
]];
var grid = new dojox.grid.DataGrid({
id: 'searchResultsGrid',
store: newStore,
structure: layout,
autoHeight:true, autoWidth:true, editable:true, columnReordering:true,
rowSelector: '20px'
});
grid.placeAt("gridDiv");
grid.startup();
}
else {
grid.setStore(newStore);
}
}
});
}
Now, when I try to make the grid editable and persist the changes to server, nothing happens with the ItemFileWriteStore. So I want to switch to JsonRestStore so that I can persist.
But the question is, how do I tie my form submit to the JsonRestStore or in other words is there a way to pass a dynamic query to the JsonRestStore ?
I want the JsonRestStore to fetch data on submit of my search form and based on the values in the search form.
Thanks in advance!
I would use the dojo.store.JsonRest store. In order to use the JsonRest store with dojox.grid.DataGrid, you will need to wrap it in a dojo.data.ObjecStore like below:
var newStore = new dojo.store.JsonRest({
target: '/search/',
idProperty: 'id'
});
newStore = new dojo.data.ObjectStore({
objectStore: newStore
});
Now the /search/ target should be your REST url. Your backend for /search/ should be able to support REST, which means you should be able to support GET, PUT, POST, DELETE requests. Take a look at http://dojotoolkit.org/reference-guide/1.10/quickstart/rest.html its for Dojo 1.10, but the method for implementing the backend should be similar.
Once you have the REST backend implemented to be able to retrieve and update data. You can send query parameters to the REST backend by setting the query parameter in the grid.
grid.setQuery({
param1: 1,
param2: 2
});
This will trigger the JsonRest store to use the url /search/?param1=1&param2=2 to load the refresh set of data in the grid.

How to add a row hyperlink for an extJS Grid?

Can someone please throw some light on how to go about rendering an hyperlink in the cells of a particular column in ExtJS?
I have tried binding the column to a render function in my JS, from which I send back the html:
SELECT
However, with this, the problem is that, once I hit the controller through the link, the navigation is successful, but subsequent navigations to the data-grid show up only empty records.
The records get fetched from the DB successfully through the Spring MVC controller, I have checked.
Please note that this happens only once I use the row hyperlink in the extJS grid to navigate away from the grid. If I come to the grid, and navigate elsewhere and again come back to the grid, the data is displayed fine.
The problem only occurs in case of navigating away from the grid, using the hyperlink rendered in one/any of the cells.
Thanks for your help!
This is for ExtJS 4 and 5.
Use a renderer to make the contents look like a link:
renderer: function (value) {
return ''+value+'';
}
Then use the undocumented, dynamically generated View event cellclick to process the click:
viewConfig: {
listeners: {
cellclick: function (view, cell, cellIndex, record, row, rowIndex, e) {
var linkClicked = (e.target.tagName == 'A');
var clickedDataIndex =
view.panel.headerCt.getHeaderAtIndex(cellIndex).dataIndex;
if (linkClicked && clickedDataIndex == '...') {
alert(record.get('id'));
}
}
}
}
Try something like this:
Ext.define('Names', {
extend: 'Ext.data.Model',
fields: [
{ type: 'string', name: 'Id' },
{ type: 'string', name: 'Link' },
{ type: 'string', name: 'Name' }
]
});
var grid = Ext.create('Ext.grid.Panel', {
store: store,
columns: [
{
text: 'Id',
dataIndex: 'Id'
},
{
text: 'Name',
dataIndex: 'Name',
renderer: function (val, meta, record) {
return '' + val + '';
}
}
...
...
...
However my thanks to - ExtJS Data Grid Column renderer to have multiple values
Instead of using an anchor tag, I would probably use plain cell content styled to look like an anchor (using basic CSS) and handle the cellclick event of the GridPanel to handle the action. This avoids dealing with the anchor's default click behavior reloading the page (which is what I'm assuming is happening).
I created a renderer so it looked like you were clicking on it.
aRenderer: function (val, metaData, record, rowIndex, colIndex, store){
// Using CellClick to invoke
return "<a>View</a>";
},
But I used a cell event to manage the click.
cellclick: {
fn: function (o, idx, column, e) {
if (column == 1) // Doesn't prevent the user from moving the column
{
var store = o.getStore();
var record = store.getAt(idx);
// Do work
}
}
}
For these purposes I use CellActions or RowActions plugin depending on what I actually need and handle cell click through it.
If you want something that looks like an anchor, use <span> instead and do what #bmoeskau suggested.
You can use 'renderer' function to include any HTML you want into cell.
Thanks guys for your response.
AFter debugging the extJS-all.js script, I found the issue to be on the server side.
In my Spring MVC controller, I was setting the model to the session, which in the use-case I mentioned earlier, used to reset the "totalProperty" of Ext.data.XmlStore to 0, and hence subsequent hits to the grid, used to display empty records.
This is because, ext-JS grid, checks the "totalProperty" value, before it even iterates through the records from the dataStore. In my case, the dataStore had data, but the size was reset to null, and hence the issue showed up.
Thanks to all again for your inputs!

How to update a Dojo Grid cell value using a TooltipDialog (and DropDownButton)

I have a dojo grid which is using some editable dijit form fields. All is well, until I try ot implement an country (multi) select cell as an Tooltip Dialog; i.e., show a drop down button which opens the tooltip dialog populated with a checkbox array to select one or more country. Once checked and clicked OK, the cell should update with a list of selected countries. Obviously I'll take care of updating the server via the store later on.
I've implemented a country select tooltip dialog which works fine like so:
dojo.provide("CountrySelector");
dojo.declare(
"CountrySelector",
[dijit.form.DropDownButton],
{
label: 'Countries',
dropDown: new dijit.TooltipDialog({ execute: function() {
console.log("EXECUTE : ", arguments[0]);
this.value = arguments[0].country;
}, href:'/cm/ui/countries' }),
postCreate: function() {
this.inherited(arguments);
this.label = this.value;
dojo.connect(this.dropDown, 'onClose', function() { console.log('close'); });
console.log("CountrySelect post create", this);
},
}
);
And the grid cell is typed as:
{ name: 'Countries', field: 'targeting.countries', editable: true, hidden: false, type:dojox.grid.cells._Widget, widgetClass: CountrySelector },
All is working fine but I can't figure out how to update cell's content and store once the widget is executed. As well, I don't seem to have the row id of the updated row.
Any ideas?
Thanks,
Harel
//Layout:
gridLayout: {rows: [{name: 'Coll Name',field: 'colField', type: dojox.grid.cells.ComboBox, editable:'true', width:'8%',options: [], alwaysEditing:false}]}
//Grid Store:
this.gridStore = new dojo.data.ItemFileReadStore({data: {items: data}});
//
var setOptions = function(items, request){
this.gridLayout.rows[0].options.push('Val 1','Val 2');
this.gridLayout.rows[0].values.push('1','2');
dojo.connect(this.gridLayout.rows[0].type.prototype.widgetClass.prototype, "onChange",this, "_onComboChange");
}
this.gridStore.fetch({onComplete: dojo.hitch(this,setOptions)});
_onComboChange: function (selectedOption) {
console.info("_onComboChange: ",selectedOption);
},
// If you need to populate combos with different values you can use onItem
var getArray = function(item, request){
// populate one by one
// attach an event to each combo
}
this.gridStore.fetch({onItem: dojo.hitch(this,getArray)});
This is what i used to update my grid
var idx = yourGrid.getItemIndex(item);
if (idx >- 1) {
yourGrid.updateRow(idx);
}
More detail
every row is identified by its identifier
yourGrid.store.fetchItemByIdentity({
identity: <yourIdentity>,
onItem: function(item){
// Update your attributes in the store depending on the server response
// yourGrid.store.setValue(item, <attribute>,<value>);
var idx = yourGrid.getItemIndex(item);
if (idx >- 1) {
yourGrid.updateRow(idx);
}
}
});
I didn't set up a test with your code but you should be able to do it by just creating a method named getValue in your widget that returns the value.
Take a look at the other examples (like dojox.grid.cells.ComboBox) to get an idea of what getValue should look like.

Resources