In ExtJS 6.02 is it possible to have a field model that is optional but also has validation?
Example an email field that may or not be present but the email must be valid if it exists.
Ext.define('my_model', {
extend : 'Ext.data.Model',
identifier: {
type : 'sequential',
seed : 1,
increment : 1
},
fields: [{
name : 'date',
type : 'date'
}, {
name : 'msg',
type : 'string',
}, {
name : 'email',
type : 'string',
}],
validators: {
date: {
type: 'presence'
},
msg: {
type : 'length',
min : 2
},
email: {
type : 'email'
}
}
});
You can override matcher of email validator to allow empty string:
Ext.define('my_model', {
extend: 'Ext.data.Model',
identifier: {
type: 'sequential',
seed: 1,
increment: 1
},
fields: [{
name: 'date',
type: 'date'
}, {
name: 'msg',
type: 'string',
}, {
name: 'email',
type: 'string',
allowBlank: true
}],
validators: {
date: {
type: 'presence'
},
msg: {
type: 'length',
min: 2
},
email: {
type: 'email',
// Override matcher to allow empty string
matcher: /^$|^(")?(?:[^\."])(?:(?:[\.])?(?:[\w\-!#$%&'*+\/=?\^_`{|}~]))*\1#(\w[\-\w]*\.){1,5}([A-Za-z]){2,6}$/
}
}
});
Ext.application({
name: 'Fiddle',
launch: function () {
var myModel = Ext.create('my_model', {
date: new Date(),
msg: 'Some Message',
//email: 'mustermann#gmail.com',
email: '',
});
console.log(myModel.isValid());
}
});
Related
I'm trying to multiple populate in sails js using sails-hook-deep-orm. I want to filter the province id.
I am using the latest version of Sails and Node. And I using MySQL for database.
This is my model :
// Province.js
attributes: {
name: {
type: 'string',
required: true
},
description: {
type: 'string',
required: false
},
cities: {
collection: 'city',
via: 'province'
}
}
// City.js
attributes: {
name: {
type: 'string',
required: true
},
description: {
type: 'string',
required: false
},
province: {
model: 'province'
},
communities: {
collection: 'community',
via: 'city'
}
}
// Community.js
attributes: {
name: {
type: 'string',
required: true
},
description: {
type: 'string',
required: false
},
cities: {
collection: 'city',
via: 'province'
}
}
I have try with :
Community.find()
.populate('city.province', {'city.province.id' : 1});
Community.find()
.populate('city.province', { where: { 'city.province.id': 1 } });
The code still not filtering. I Hope this case can be solved. Thank you :)
When you populate an association of your object, the name needs to be the name of the association in the parent object and not the name of the model you are referring to.
In your situation, Community has the association named 'cities'.
The next step is to filter the list of cities, this is the where statement as the second argument of the populate.
Community.find()
.populate('cities', {
where: {
province: 1
}
}
)
I have 2 Models, User and Post. I want to be able to get User information when querying a post, and be able to get all of a User's posts when querying a user.
they have an association as follows:
User.hasMany(Post, {
foreignKey: 'user',
as: 'posts'
});
Post.belongsTo(User, {
foreignKey: 'id',
sourceKey: 'user',
as: 'userObject'
})
Post.addScope('defaultScope', {
include: [{ model: User, as: 'userObject' }],
}, { override: true })
User.addScope('defaultScope', {
include: [{ model: Post, as: 'posts' }],
}, { override: true })
Here are my Models
User.js
module.exports.userType = new GQL.GraphQLObjectType({
name: 'User',
fields: () => {
const { postType } = require('../Post/Post');
return {
id: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'user unique id'
},
ci_username: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
unique: true,
description: 'case INSENSITIVE username of the user'
},
username: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'case SENSITIVE username of the user'
},
password: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'password for the user'
},
first_name: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'first name of user'
},
last_name: {
type: GQL.GraphQLString,
description: 'last name of user (optional)'
},
profile_picture: {
type: GQL.GraphQLString,
description: 'profile picture for the user'
},
posts: {
type: GQL.GraphQLList(postType),
description: 'list of users posts'
}
}
},
})
/** define User model for the database */
module.exports.User = db.define('user', {
id: {
type: Sequelize.UUID,
primaryKey: true,
unique: true,
},
ci_username: {
type: Sequelize.STRING,
unique: true,
},
username: Sequelize.STRING,
password: Sequelize.STRING,
first_name: Sequelize.STRING,
last_name: Sequelize.STRING,
profile_picture: Sequelize.STRING,
}, {
// Tells sequelize not to query the "CreatedAt" or "UpdatedAt" Columns
timestamps: false
})
Post.js
module.exports.postType = new GQL.GraphQLObjectType({
name: 'Post',
fields: () => {
const { userType } = require('../User/User');
return {
id: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'post unique id'
},
name: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'name of the post'
},
user: {
type: userType,
description: 'user object of who created the post'
},
created_at: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'the datetime the post was created',
}
}
},
})
/** define User model for the database */
module.exports.Post = db.define('post', {
id: {
type: DataTypes.UUID,
primaryKey: true,
unique: true,
},
name: DataTypes.STRING,
user: {
type: DataTypes.STRING,
references: {
model: 'users',
key: 'id'
}
},
created_at: {
type: DataTypes.TIME,
defaultValue: DataTypes.NOW
}
}, {
// Tells sequelize not to query the "CreatedAt" or "UpdatedAt" Columns
timestamps: false
})
Here are my Queries:
allUsers.js
const allUsers = {
type: new GQL.GraphQLList(userType),
args: {
username: {
description: 'username of the user',
type: GQL.GraphQLString,
},
// An arg with the key limit will automatically be converted to a limit on the target
limit: {
type: GQL.GraphQLInt,
default: 10
},
// An arg with the key order will automatically be converted to a order on the target
order: {
type: GQL.GraphQLString
}
},
// use graphql-sequelize resolver with the User model from database
resolve: resolver(User)
}
allPosts.js
const allPosts = {
type: new GQL.GraphQLList(postType),
args: {
username: {
description: 'username of the user',
type: GQL.GraphQLString,
},
// An arg with the key limit will automatically be converted to a limit on the target
limit: {
type: GQL.GraphQLInt,
default: 10
},
// An arg with the key order will automatically be converted to a order on the target
order: {
type: GQL.GraphQLString
}
},
// use graphql-sequelize resolver with the Post model from database
resolve: resolver(Post)
}
I'm currently getting a Maximum call stack size exceeded. I assume because the resolver in the queries are recursively getting details on posts and users infinitely.
Does anyone know of any way to put a depth limitation on the resolver? Or is it just not possible to have a recursive query like this?
You would have to remove the default scope from the included model as shown here like this:
Post.addScope('defaultScope', {
include: [{ model: User.scope(null), as: 'userObject' }],
}, { override: true })
User.addScope('defaultScope', {
include: [{ model: Post.scope(null), as: 'posts' }],
}, { override: true })
To support additional depth, you'd need to implement resolvers for the fields in question, for example:
function resolve (user) {
if (user.posts) {
return user.posts
}
return user.getPosts()
}
trying to make this work....
I want to load nested data on two object model
Ext.application({
name : 'MyApp',
launch : function() {
Ext.define('MyApp.model.Address', {
extend: 'Ext.data.Model',
entityName: 'Address',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressLine',
type: 'string'
},
{
name: 'city',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
entityName: 'User',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'address',
reference: 'Address'
},
{
name: 'name',
type: 'string'
},
{
name: 'lastname',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
var user = new MyApp.model.User({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"address": {
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
},
"created": 1420668866000
});
console.info(user);
console.info(user.getAddress());
}});
It's result on no error when created the user, but when I access to associated data via user.getAddress() it returned an exception:
Uncaught Error: The model ID configured in data ("[object Object]") has been rejected by the int field converter for the id fieldext-all-debug.js
Try to define proxy like memory or localstorage on model definitions, but the result it is the same.
Ext fiddle: https://fiddle.sencha.com/#fiddle/h2d
Any help will be appreciated!
Solved, but only find this solution: when use loadRawData...
var store = new Ext.data.Store({
model: MyApp.model.User
});
store.loadRawData({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"address": {
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
},
"created": 1420668866000
});
console.info(store.first());
console.info(store.first().getAddress());
sample at this new fiddle: https://fiddle.sencha.com/#fiddle/h4e
you'r right, ext is a bit flaky, very....
I've been playing around with the code in your fiddle and not been able to get the association working the official way as of yet.
I simulated the functionality using this code:
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'name',
type: 'string'
}, {
name: 'lastname',
type: 'string'
}, {
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}],
getAddress: function() {
if ('undefined' === this.data.address) {
return null;
}
return Ext.create('Address', this.data.address);
}
});
Basically I've removed the association and created a custom function to create a model record based off of the raw data passed in, You could also return a new, empty model if the address data does not exist instead of null, I used null as it's easier to determine whether you have a valid address record or not.
As already mentioned - this is not the official way to do this, I will have another play around with the fiddle and post a better solution once I find it, this may help in the meantime.
Using the original code, I made a few modifications and now it appears to be working.
Ext.application({
name : 'MyApp',
launch : function() {
Ext.define('MyApp.model.Address', {
extend: 'Ext.data.Model',
//entityName: 'Address',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressLine',
type: 'string'
},
{
name: 'city',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
],
hasMany: 'User'
});
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
//entityName: 'User',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'name',
type: 'string'
},
{
name: 'lastname',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
],
hasMany: { model: 'Address', name: 'Address' }
});
var user = new MyApp.model.User({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"address": {
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
},
"created": 1420668866000
});
console.info(user);
console.info(user.data.address);
}
});
Is this the sort of thing you're after? I set Address manually on the User model. Not ideal but it's interpreted correctly as a record then.
Ext.define('MyApp.model.Address', {
extend: 'Ext.data.Model',
entityName: 'Address',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressLine',
type: 'string'
},
{
name: 'city',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
entityName: 'User',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressId',
reference: 'Address'
},
{
name: 'name',
type: 'string'
},
{
name: 'lastname',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
var user = new MyApp.model.User({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"created": 1420668866000
});
var addr = new MyApp.model.Address({
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
});
user.setAddress(addr);
console.info(user);
console.info(user.getAddress());
I am using Sencha Touch to display nested (associated) model data in a list template but I can only get the root model data to display. My models are an Appointment which belongs to a Customer, and Customers have many Appointments. My model code:
Customer = Ext.regModel('Customer', {
hasMany: { model: 'Appointments', name: 'appointments' },
fields: [
{ name: 'id', type: 'integer' },
{ name: 'firstName', type: 'string' },
{ name: 'lastName', type: 'string' },
{ name: 'email', type: 'string' },
{ name: 'secondary_email', type: 'string' },
{ name: 'homePhone', type: 'string' },
{ name: 'mobilePhone', type: 'string' },
{ name: 'dob', type: 'date', dateFormat: 'Y-m-d' },
{ name: 'allowLogin', type: 'boolean' },
{ name: 'emailReminders', type: 'boolean' },
{ name: 'reminders_to_stylist', type: 'boolean' },
{ name: 'fullName',
convert: function(value, record) {
var fn = record.get('firstName');
var ln = record.get('lastName');
return fn + " " + ln;
} }
]
});
Appointment = Ext.regModel('Appointment', {
belongsTo: { model: 'Customer', name: 'customer' },
fields: [
{ name: 'id', type: 'string' },
{ name: 'startTime', type: 'date', dateFormat: 'c' },
{ name: 'customer_id', type: 'integer' },
{ name: 'startTimeShort',
convert: function(value, record) {
return record.get('startTime').shortTime();
}
},
{ name: 'endTimeShort',
convert: function(value, record) {
return record.get('endTime').shortTime();
}
},
{ name: 'endTime', type: 'date', dateFormat: 'c' }
]
});
And my panel using an xtype: list looks like:
var jsonPanel = {
title: "Appointments",
items: [
{
xtype: 'list',
store: appointmentStore,
itemTpl: '<tpl for="."><span id="{id}">{startTimeShort} - {endTimeShort} <tpl for="customer"><span class="customer">{firstName}</span></tpl></span></tpl>',
singleSelect: true,
onItemDisclosure: function(record, btn, index) {
Ext.Msg.alert('test');
}
}
]
};
The nested data gets loaded from JSON and appears to be loading correctly into the store - when I debug the appointment store object loaded from the Appointment model, I see that the appointment.data.items array objects have a CustomerBelongsToInstance object and that object's data object does contain the correct model data. The startTime and endTime fields display correctly in the list.
I have a suspicion that I am either not using the item template markup correctly, or perhaps there is some weird dependency where I would have to start from the model that has the "has many" association rather than the "belongs to" as shown in the kitchen sink demo.
I wasn't able to find any examples that used this type of association so any help is appreciated.
Looks like your Customer hasmany association is assigning Appointments when it should be appointment which is the name of that model.
The Store
var timesheet = new Ext.data.JsonStore(
{
root: 'timesheetEntries',
url: 'php/scripts/timecardEntry.script.php',
storeId: 'timesheet',
autoLoad: true,
fields: [
{ name: 'id', type: 'integer' },
{ name: 'user_id', type: 'integer' },
{ name: 'ticket_number', type: 'integer' },
{ name: 'description', type: 'string' },
{ name: 'start_time', type: 'string' },
{ name: 'stop_time', type: 'string' },
{ name: 'client_id', type: 'integer' },
{ name: 'is_billable', type: 'integer' }
]
}
);
A section of my GridPanel code:
columns: [
{
id: 'ticket_number',
header: 'Ticket #',
dataIndex: 'ticket_number'
},
{
id: 'description',
header: 'Description',
dataIndex: 'description'
},
{
id: 'start_time',
header: 'Start',
dataIndex: 'start_time',
renderer: Ext.util.Format.dateRenderer('m/d/Y H:i:s')
}
...
From the server, I receive this JSON string:
{
timesheetEntries:[
{
"id":"1",
"user_id":"1",
"description":null,
"start_time":"2010-11-13 11:30:00",
"stop_time":"2010-11-13 15:50:10",
"client_id":null,
"is_billable":"0"
}
My grid panel renders fine. However, my start and stop time columns read 'NaN/NaN/NaN NaN:NaN:NaN' and I don't know why.
If your data has "2010-11-13 11:30:00" shouldn't your format be 'Y-m-d H:i:s'?
EDIT: Sorry, the grid config should be OK -- I was referring to the dateFormat value in your store's field definition, which should be 'Y-m-d H:i:s' so that your incoming data can be properly mapped to your column model. You should also include type: 'date'. You're not showing your store config, but the problem is likely one of those things being wrong.
Try this
function renderDate(v,params,record)
{
var dt = new Date(v);
if (!isNaN(dt.getDay())) {
return dt.format('d/m/Y');
}
return '-';
}
A very simple way to do it:
return Ext.util.Format.date(val,'m/d/Y');