I am occassionally ( usually 1 in 3 page loads) receive the following error message
view is undefined
view.onItemSelect(record);
In my view
{
xtype:'combobox',
name:'PurchaseOrderStatusId',
id:'PurchaseOrderStatusCombo',
displayField:'Name',
store:'PurchaseOrderStatuses',
mode:'local',
valueField:'Id',
fieldLabel:'Status',
width: 350
},
{
xtype:'combobox',
name:'SupplierId',
id:'SupplierCombo',
displayField:'Name',
store:'Suppliers',
mode:'local',
valueField:'Id',
fieldLabel:'Suppliers',
width: 350
},
// in my controller
onLaunch: function () {
var suppliers = this.getSuppliersStore();
suppliers.load();
var purchaseOrderStatuses = this.getPurchaseOrderStatusesStore();
purchaseOrderStatuses.load();
var purchaseOrdersStore = this.getPurchaseOrdersStore();
purchaseOrdersStore.load({
callback: this.onPurchaseOrderLoad,
scope: this
});
},
onPurchaseOrderLoad: function (selection) {
var form = Ext.getCmp('purchaseOrderForm');
form.loadRecord(selection[0]);
},
in my model
{
mapping:'PurchaseOrderStatusId',
name:'PurchaseOrderStatusId'
},
{
mapping:'SupplierId',
name:'SupplierId'
}
It's not clear how the error message you are reporting is linked to any of the code you have revealed so far. So it's difficult to connect the dots here.
However here are a couple of observations:
1. If you need your stores to always load ASAP when your app launches set the autoLoad:true config on those stores. This way you don't have to explicitly load them and they have more time to finish loading before your view is ready to go.
2. If you need to load an instance of your model into the form you can use Model.load method instead of having a store do that for you. You will need to provide API on the model on how to read the records from the server.
3. Model mapping is not necessary if your Model fields match to what the server returns.
If you need further help, please update your question with some more debug info.
Related
I am developing a react native application with apollo client and I need to have 2 screens:
Screen A: displays a list of profiles
Screen B: displays some filters which have to be applied to Screen A
So my idea was to use apollo client cache to save the state of the filters in screen B, and then come back to screen A and somehow refetch with the new filters applied.
Since there are a couple of filters that I need to send on each request to the server, I also was thinking about using an input type so I can send my filters in the form of an object instead of a list of comma-separated parameters.
So looking at the docs from apollo client, there is a section to manage the local stage. In there, I found a sub-section called Using #client fields as variables. Basically, this part tells you how to grab whatever filters were stored in the cache and send it as part of the query.
However, I always get the following error:
Invariant Violation: Missing selection set for an object of type ProfileParameters returned for query field profileParameters
some code:
This is how I initialized the cache-store, for now, it only contains page and pageSize but it will contain more parameters.
const cache = new InMemoryCache({
cacheRedirects: {
Query: {
profile: (_, {id}, {getCacheKey}) =>
getCacheKey({__typename: 'Profile', id: id}),
},
},
});
cache.writeData({
data: {
profileParameters: {
__typename: 'ProfileParameters',
page: 0,
pageSize: 25,
},
},
});
const client = new ApolloClient({
uri: 'http://192.168.1.102:3000/graphql',
cache: cache,
resolvers: {},
});
And this is the query component and the query:
const PROFILES_QUERY = gql`
query getFilteredProfiles($type: String, $parameters: ProfileParameters) {
profileParameters #client #export(as: "parameters")
profiles(type: $type, parameters: $parameters) {
id
name
termOfEntry
sport
sportPosition
gpa
avatarUrl
imageUrl
nationality
countryOfResidence
dateOfBirth
annualBudget
career
satScore
toeflScore
graduationDate
}
}
`;
<Query
query={PROFILES_QUERY}
variables={{
type: this.PROFILE_TYPE,
}}>
...
</Query>
There is a type variable that is being passed in the variables object. That comes from a local variable in the class.
Also, screen B does not exist yet, but the cache is being initialized and I want to read whatever is in there so I can send those filters to the server.
I've got two editable feature layers in my application, and I'm trying to attach the appropriate attribute inspector depending on which feature layer my user is trying to edit.
I create the Attribute Inspectors for both feature layers when my application loads and then attach the appropriate attribute inspector to the map's InfoWindow when the user is trying to edit a feature layer.
All works well, until the user tries to edit another feature layer. When I try and attach a different attribute inspector to the infowindow, it just comes up blank.
Here's roughly what I'm doing:
// AttributeEditor1 for FeatureLayer1 in Class1
constructor: function(options) {
this.options = lang.mixin(this.options, options);
this.map = options.map;
this.configureAttributeEditor1();
},
configureAttributeEditor1: function() {
this.attributeEditor1 = new AttributeInspector({
layerInfos: layerInfos
}, domConstruct.create("div"));
// here I add a Save and Delete button and various event handlers
this.attributeEditor1.startup();
},
// I call this when I know that the user wants to edit FeatureLayer 1
attachEditor1: function() {
this.map.infoWindow.setContent(this.attributeEditor1.domNode);
this.map.infoWindow.resize(350, 240);
},
// AttributeEditor2 for FeatureLayer2 in Class2
constructor: function(options) {
this.options = lang.mixin(this.options, options);
this.map = options.map;
this.configureAttributeEditor2();
},
configureAttributeEditor2: function() {
this.attributeEditor2 = new AttributeInspector({
layerInfos: layerInfos
}, domConstruct.create("div"));
// here I add a Save and Delete button and various event handlers
this.attributeEditor2.startup();
},
// I call this when I know that the user wants to edit FeatureLayer 2
attachEditor2: function() {
this.map.infoWindow.setContent(this.attributeEditor2.domNode);
this.map.infoWindow.resize(350, 240);
},
Thanks in advance.
When you update the content of infoWindow using map.infoWindow.setContent, it destroys the previous content and then updated the new content. So basically your AttributeInspector1 will be destroyed when you updated the info window with AttributeInspector2.
You need not create multiple AttributeInspector, while working on multiple FeatureLayer. The layerInfos property is an array type, you could set upd multiple layers.
But, I guess you have different needs/actions to be taken when you switch between layers. The best thing you could do is to either create new AttributeInspector every time you switch, or just update the layerInfos and save and delete events. Make sure you remove the previous save and delete event handles.
I'm trying to get a KendoUI grid working with server side paging. So far I've managed to get the grid reading data from the remote datasource and correctly sending paging/filtering information to an MVC controller action
This is working fine, however, I don't see the paging controls for the grid at all.
I've tried adding pageable: true to the setup of the grid, and although this does display the pager control, it doesn't show any pages/totals and throws a JS object does not support this property or method when I try and change the page using the next/prev page buttons. The method it's looking for is 'slice' - I'm going to have a look at the non-minified kendo src but in the meantime I thought I'd post here
The action looks like this:
public ActionResult _Index(int? pageSize, int? skip, string filter = "")
{
// Code that gets the data
var data = ... (some Linq->Entities queries)
var total = ... (total count of all the entities)
return Json(new { total, data });
}
I'm correctly returning the total, and I've checked the JSON and it matches what I'm expecting (and what the grid should be expecting)
The grid setup is this:
$(document).ready(function () {
var grid = $("#itemList").kendoGrid({
toolbar: kendo.template($("#template").html()),
columns: ["Manufacturer", "Model", "Price", "Tags"],
dataSource: {
transport: {
read: {
url: "catalogadmin/_index",
dataType: "json",
type: "POST",
data: {
filter: ""
}
},
},
schema: {
data: "data", // records are returned in the "data" field of the response
total: "total" // total number of records is in the "total" field of the response
},
pageSize: 2,
serverPaging: true
},
pageable: true
});
I set the pageSize to 2 to test paging (as I only have 4 items in the DB at the mo)
JSON is:
{"total":4,"data":[{"Id":6,"Manufacturer":"hello","Model":";lmqw;lemwqe","Price":4.00,"ShortDescription":"world","Tags":[],"Used":false}]}
I don't think that's the issue though - it seems like you need to set pageable: true to get paging working - but I don't think the paging even works with client side data, I'm just going to check now
Edit: I've checked and client-side paging doesn't work either. I get an 'Unable to get property toLowerCase of undefined or null reference' when trying to page. The pager looks like the server side page, no data, no page numbers, no totals.
I'm thinking Kendo isn't quite registered right - I've got the very latest version (just downloaded it now) but no cigar...
Sorted - not sure why but when I installed KendoUI using Teleriks 'convert to Kendo UI project' it registered both the kendo.all.min.js file and also the mvc/dataviz ones.
I removed the extra script references and it's all working now!
I want to stress that this problem only occurs outside of a template, such as when I try to access properties of related objects while in a controller, unit test, etc. Rendering the template seem to get the property well and work as expected.
Here is a simple example in JS Bin with a failing test http://jsbin.com/ihumuk/4/edit which repros my problem. The passing test asserts that the property is accessible and rendered in the template as expected. The failing test shows that I get null when I try to access the property with get. Really nothing fancy here but I don't understand why it's returning null.
Here is the application part of the JS Bin example:
App.ApplicationRoute = Em.Route.extend({
model: function() {
return App.Foo.find();
}
});
App.Store = DS.Store.extend({
adapter: DS.FixtureAdapter.create()
});
App.Foo = DS.Model.extend({
name: DS.attr("string"),
/**
* The subject under test
*/
childName: function() {
return this.get("child.name");
}.property("child.name"),
child: DS.belongsTo("App.Bar")
});
App.Bar = DS.Model.extend({
name: DS.attr("string")
});
App.Foo.FIXTURES = [{
id: 1,
name: "Fred",
child: 3
}, {
id: 2,
name: "Barney",
child: 4
}];
App.Bar.FIXTURES = [{
id: 3,
name: "Pebbles"
}, {
id: 4,
name: "Bam Bam"
}];
This passes.
test("Child name is rendered", function() {
expect(1);
visit("/").then(function() {
ok(find("div:contains(Pebbles)").length);
});
});
This fails.
test("Child name is accessed", function() {
expect(2);
var foo = App.Foo.find(1);
equal(foo.get("childName"), "Pebbles");
equal(foo.get("child.name"), "Pebbles");
});
This has to be something simple/stupid like forgetting a character or something, but I think I've driven myself too far into frustration to think clearly for a while. Thanks in advance for any help.
You need to use the then to know when the data is loaded
asyncTest("Child name is accessed", function() {
expect(2);
// load the data from server
App.Foo.find(1).then(function(foo) {
// the child id is 3, we need to fetch the remaining data
// and this is async, because of the ajax request
foo.get("child").then(function(child) {
equal(child.get("name"), "Pebbles");
// childName call child.name, but since the
// data is loaded, isn't necessary to use a second then
equal(foo.get("childName"), "Pebbles");
start();
});
});
});
In ember data, like major of the orm's, the data is lazy loaded, for relationships. This is because, isn't needed to return all loaded object graph, let's leave the user ask for what it want, and then load.
Because some implementations are async, like: websql, indexeddb, ajax, websockets etc. The interface of ember-data is async, so you need to use the then method to know when the data is loaded or failed.
The things work in your template, because it are binding aware. Even when the change are async, it will be finished later, and the bindings will be notified and updated.
I have updated your demo, and the tests pass http://jsbin.com/eqojaj/1/edit
I have created a Sencha Touch 2 app and built a production mode version. However, I have encountered a big issue with the production build and it running in Phone/Tablet modes.
The current profile implementation of ST2 seems flawed as even if you have a specific profile activated, all views are still loaded in. In my application I want to be able to specify views using the xtype alias in the view config, and have the correct view for phone or tablet profile loaded in without any special coding. If all views from profiles are loaded in then this can't work (one view will always override another).
The only way I could achieve this was to dynamically add the profile at bootup stage (within app.js) like so:
Ext.application({
name: 'MyTestApp',
var activeProfile = Ext.os.is.Phone ? ['Phone'] : ['Tablet'];
requires: [ ... ],
profiles: activeProfile
});
This has worked fine. It means I can then load the correct view and still just use the xtype alias within the config of another view and/or ref in a controller. However, I noticed that when I generate a production build and load up a console window, both of the following are defined:
MyTestApp.views.phone.Login
MyTestApp.views.tablet.Login
Normally the tablet or phone version would be undefined depending on the profile. I'm assuming this is the case because the production mode build has parsed ALL dependencies and then included all views regardless of the profile.
So in my start-up controller I have a button handler which then creates a login view from the xtype.
Controller:
refs: {
loginView: {
selector: 'loginview',
xtype: 'loginview',
autoCreate: true
}
}
Handler:
var loginView = this.getLoginView();
In development mode, the loginView variable will either be MyTestApp.views.tablet.Login or MyTestApp.views.phone.Login depending on the profile.
How do I ensure that the loginview instantiated here gets the correct version depending on the profile when in production mode?
I had been struggling with this, when I would move either of the solutions to the devices, I would be stuck with the fact that all views are referenced and would get some xtype collision always giving me the phone view. ( i had to move to aliases eventually - not sure why :( ). I finally managed to crack this for my use case, just sharing for future reference.
I am running touch 2.3.1 and cordova 3.3.1 with the latest cmd 4.0.2.67
I use the solution from Christopher except I had to change the source code in the sencha touch source directory rather than keep it in the app.js [truthfully I don't know why it hangs when I leave it as an override]
In addition I have had to configure the views the following way in order for:
define a base class for the view with an alias so the controller to understand the ref as it loads first
dynamically assign the alias to the view instantiated by the profile
strip out (using Christopher code)
Base class for the views
Ext.define('MyApp.view.CatalogView', {
extend: 'Ext.Container',
alias: 'widget.catalogview'
});
Assign an alias to the profile specific view
Ext.define('MyApp.profile.Phone', {
extend: 'Ext.app.Profile',
config: {
name: 'Phone',
views: ['CatalogView'],
},
isActive: function() {
return Ext.os.is('Phone');
},
launch: function() {
Ext.ClassManager.setAlias('MyApp.view.phone.CatalogView', 'widget.catalogview');
}
});
Repeat for the tablet view
For all who want to know how I resolved this, I'm now left bald after pulling all my hair out;)
All my profile views where I want to have the xtype names remain the same even though they might belong in the phone or tablet profiles, I have to remove the alias/xtype config on the class. I then have a profile base class defined like so with a shared helper function:
Ext.define('MyApp.profile.Base', {
extend: 'Ext.app.Profile',
config: {
},
mapViewAliases: function () {
var self = this;
var views = this.getDependencies().view;
var newAliasMap = null;
Ext.each(views, function (view) {
Ext.Array.some(self.getViewsToAliasMap(), function (map) {
if (map[view]) {
if (!newAliasMap) {
newAliasMap = {};
}
newAliasMap[view] = [map[view]];
return true;
}
});
});
if (newAliasMap) {
console.log('view aliases being mapped for: ' + this.$className);
Ext.ClassManager.addNameAliasMappings(newAliasMap)
}
}
});
Then I have the profile class inherit from the base class (this is repeated with the tablet profile except the viewsToAliasMap holds classes belonging to the tablet profile instead of the phone profile):
Ext.define('MyApp.profile.Phone', {
extend: 'MyApp.profile.Base',
config: {
name: 'Phone',
views: ['Login', 'Home', 'Welcome' ],
viewsToAliasMap: [
{ 'MyApp.view.phone.Login': 'widget.loginview' },
{ 'MyApp.view.phone.Home': 'widget.homeview' },
{ 'MyApp.view.phone.Welcome': 'widget.welcomeview' }
]
},
isActive: function () {
return Ext.os.is.Phone;
},
launch: function () {
console.log("Phone profile launched");
this.mapViewAliases();
}
});
So basically, the profile calls the function mapViewAliases() on the base class in the launch function. The mapViewAliases() registers the view class names with the aliases defined in the profile with the class manager. So effectively the xtype names are resolved at run-time.
I'm sure this code can be improved and/or a better way to do this.
Please feel free to let me know.
I am using a pretty naive implementation... I'm sure it could be made more robust, but I've been hacking at this for 5 hours or so now.
Ext.define('MyApp.override.Application', {
override : 'Ext.app.Application',
onProfilesLoaded: function() {
var profiles = this.getProfiles(),
length = profiles.length,
instances = [],
requires = this.gatherDependencies(),
current, i, profileDeps;
for (i = 0; i < length; i++) {
var instance = Ext.create(profiles[i], {
application: this
});
/*
* Note that we actually require all of the dependencies for all Profiles - this is so that we can produce
* a single build file that will work on all defined Profiles. Although the other classes will be loaded,
* the correct Profile will still be identified and the other classes ignored. While this feels somewhat
* inefficient, the majority of the bulk of an application is likely to be the framework itself. The bigger
* the app though, the bigger the effect of this inefficiency so ideally we will create a way to create and
* load Profile-specific builds in a future release.
*
CMK - PSHAW!
*/
if (instance.isActive() && !current) {
console.log('Profile active: ' + instance.getName());
current = instance;
profileDeps = instance.getDependencies();
requires = requires.concat(profileDeps.all);
var ns = instance.getNamespace();
this.setCurrentProfile(current);
// Merge Controllers, Models, Stores, and Views
this.setControllers(this.getControllers().concat(profileDeps.controller));
this.setModels(this.getModels().concat(profileDeps.model));
this.setStores(this.getStores().concat(profileDeps.store));
this.setViews(this.getViews().concat(profileDeps.view));
// Remove the view ref and requires for default views, when a profile specific one exists
Ext.each(profileDeps.view, function(className) {
if (className.indexOf('view.' + ns + '.') !== -1) {
// Requires
var index = requires.indexOf(className.replace('view.' + ns, 'view'));
if (index !== -1) {
requires.splice(index, 1);
}
// Views
index = this.getViews().indexOf(className.replace('view.' + ns, 'view'));
if (index !== -1) {
this.getViews().splice(index, 1);
}
}
}, this);
instances[0] = instance;
break;
}
}
this.setProfileInstances(instances);
Ext.require(requires, this.loadControllerDependencies, this);
}
});
Put this before your Ext.application, and it replaces the profile loader... This one strips out default views with the same name as one in the active profile namespace.
It requires that you define an xtype for the views that match, then even your refs in controllers will work...
I need to continue testing with this, but it looks promising so far.