ExtJs 5 -- Setting the proxy for a store - extjs5

I have a Store where I am trying to define its proxy in the constructor, like so:
Ext.define('App.store.LabStore', {
extend: 'Ext.data.Store',
constructor: function(config) {
var prox = new Ext.data.proxy.Ajax();
prox.setUrl('http://server:port/app/labs');
prox.setHeaders({'Content-type': 'application/json'});
prox.setReader({type: 'json',rootProperty: 'departmentList'});
this.setProxy(prox);
this.callParent(arguments);
},
autoLoad: false,
model: 'App.model.Lab'
});
Unfortunately, this won't work. What does work, from my controller, is this:
var labStore = Ext.create("App.store.LabStore");
var url = 'http://server:port/app/labs';
labStore.getProxy().setUrl(url);
labStore.on('load','checkLabs',this);
labStore.load();
I realize that the latter method works and perhaps I should just move on but I do want to try to figure out why I cannot set the proxy in the constructor and/or what I'm doing wrong with that approach.
Thanks in advance!
Frank

There is no need to define proxy in constructor. You can define all your properties in config object like so:
//define model
Ext.define('App.model.Lab', {
extend: 'Ext.data.Model',
fields: [{
name: 'name',
type: 'string'
}, {
name: 'closed',
type: 'bool'
}]
});
//define store
Ext.define('App.store.LabStore', {
extend: 'Ext.data.Store',
model: 'App.model.Lab',
proxy: {
type: 'ajax',
url: 'labs.json',
reader: {
type: 'json',
rootProperty: 'departmentList'
}
},
autoLoad: false
});
//initialize store
var store = Ext.create('App.store.LabStore');
// load data from source
store.load();
Here is a fiddle
or you can pass the proxy config when creating store class, like so:
var store = Ext.create('App.store.LabStore', {
proxy: {
type: 'ajax',
url: 'labs.json',
reader: {
type: 'json',
rootProperty: 'departmentList'
}
}
});
but if you need to do it in a constructor you can:
//define store
Ext.define('App.store.LabStore', {
extend: 'Ext.data.Store',
constructor: function(config) {
config = Ext.applyIf({
proxy: {
type: 'ajax',
url: 'labs.json',
reader: {
type: 'json',
rootProperty: 'departmentList'
}
}
}, config);
this.callParent([config]);
},
autoLoad: false
});
Here is a fiddle

The config parameter is used to initialise the Store. It includes, by default, an undefined proxy. I'd be about 90% sure that it's reseting the proxy during the call to the parent constructor.
Try setting the proxy into the config object instead.
Ext.define('App.store.LabStore', {
extend: 'Ext.data.Store',
constructor: function(config) {
var prox = new Ext.data.proxy.Ajax();
prox.setUrl('http://server:port/app/labs');
prox.setHeaders({'Content-type': 'application/json'});
prox.setReader({type: 'json',rootProperty: 'departmentList'});
config.proxy = prox;
this.callParent(arguments);
},
autoLoad: false,
model: 'App.model.Lab'
});

Related

Sequelize in Nodejs creating duplicate tables upon app start

Ok. Landscape: Node, MySql, Sequelize
Issue: After creating a new data model & migration (node migrate.js which creates just fine), upon app start Sequelize creates a duplicate Table (and also forwards form data to the new table).
Ex: db.virtual_class is the main table, and upon start, db.virtual_classes is also created.
My model:
const Sequelize = require('sequelize');
const sequelize = require('../sequelize');
const model = sequelize.define('virtual_class', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
style: Sequelize.STRING, // e.g. Style of class
description: Sequelize.STRING(1024), // e.g. class Details
jwt_secret: Sequelize.STRING, // e.g. rando string to be used to gen unique keys for every room
});
module.exports = model;
I've isolated what I think is the issue - I'm including the model in a variable on my index controller for my functions.
const Virtual_class = require('./model');
const classQuery = require('./classQuery');
async function addClass({ style, description, secret }) {
const vClass = await Virtual_class.create({
style,
description,
jwt_secret: secret,
}, { raw: true });
return classQuery(vClass);
}
module.exports = {
addClass,
};
Class Query function to return the data in a usable object:
function classQuery(queryResult) {
if (!queryResult) {
return null;
}
return {
id: queryResult.id,
style: queryResult.style,
description: queryResult.description,
secret: queryResult.jwt_secret,
};
}
module.exports = classQuery;
and the migration:
module.exports = {
up: (sequelize, Sequelize) => sequelize.getQueryInterface().createTable('virtual_class', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
style: {
type: Sequelize.STRING,
},
description: {
type: Sequelize.STRING,
},
jwt_secret: {
type: Sequelize.STRING,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
}),
down: sequelize => sequelize.getQueryInterface().dropTable('virtual_class'),
};
Net result is fine before I run app - DB shows new table, After running app - DB shows dup table.
I'm a relative noob, and been wracking my brain (and trying to find solutions here) to the problem. I've done this before with other migrations with no issue.
Any advice is appreciated! Thanks!
DOH! For those who are new like me - Sequelize automatically creates plural tables by default, You can force the override tp singular table names.

SequelizeEagerLoadingError: (parent) is not associated to (child)!

I am building an application using sequelize. I currently have 3 tables; a User, a Tour, and a Location. The Location has a n:1 relationship with the Tour. The Tour has a n:1 relationship with the user.
Without the User association, the other two tables work fine. Once I add in the user association (and I have tried to do so through a migration AND by dropping and then recreating my entire database), I get a SequelizeEagerLoadingError: Location is not associated with Tour!
Here are my models:
module.exports = function(sequelize, DataTypes) {
var Location = sequelize.define("Location", {
title: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
len: [500]
}
},
address: {
type: DataTypes.TEXT,
allowNull: false
}
});
Location.associate = function(models) {
Location.belongsTo(models.Tour, {
onDelete: "cascade"
});
};
return Location;
};
module.exports = function(sequelize, DataTypes) {
var Tour = sequelize.define("Tour", {
title: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
len: [1, 1000]
}
},
neighborhood: {
type: DataTypes.STRING,
allowNull: false
},
URL: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
len: [1, 1000]
}
},
numberOfStops: DataTypes.INTEGER,
duration: {
type: DataTypes.INTEGER,
allowNull: false
},
tags: DataTypes.STRING
});
Tour.associate = function(models) {
Tour.hasMany(models.Location);
};
Tour.associate = function(models) {
Tour.belongsTo(models.User);
};
return Tour;
};
var bcrypt = require("bcrypt-nodejs");
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define("User", {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: DataTypes.STRING,
allowNull: false
}
});
User.prototype.validPassword = function(password) {
return bcrypt.compareSync(password, this.password);
};
User.hook("beforeCreate", function(user) {
user.password = bcrypt.hashSync(
user.password,
bcrypt.genSaltSync(10),
null
);
});
User.associate = function(models) {
User.hasMany(models.Tour);
};
return User;
};
And here is the include statement where it is failing, and where we establish the link with the tourId to the location:
app.get("/tour/:id", function(req, res) {
db.Tour.findOne({
where: { id: req.params.id },
include: [db.Location]
}).then(function(tour) {
res.render("tour", {
tour: tour
});
});
});
var API = {
saveTour: function(tour) {
return $.ajax({
headers: {
"Content-Type": "application/json"
},
type: "POST",
url: "api/tours",
data: JSON.stringify(tour)
});
},
saveLocations: function(locations) {
return $.ajax({
headers: {
"Content-Type": "application/json"
},
type: "POST",
url: "api/locations",
data: JSON.stringify(locations)
});
},
getUserId: function() {
return $.ajax({
type: "GET",
url: "api/user_data"
});
}
};
var tour = {
Users: thisUser.getUserId(),
title: title,
description: description,
neighborhood: neighborhood,
URL: URL,
duration: duration,
tags: tags
};
// console.log(tour);
if (!errors.length) {
// Post our tour to the Tours table, then reveal the form and set our local tour object.
API.saveTour(tour).then(function(tour) {
document.getElementById("submit-tour").remove();
document.getElementById("tourstopssection").style.display = "block";
thisTour.setId(tour.id);
});
}
}
// Function takes in the newly created tour object, grabs DOM values for each.
function addTourLocations(e) {
e.preventDefault();
// Grab and process all of our tour stops.
var locationElements = document.getElementsByClassName("tourstop");
var areStopErrors = false;
var locations = [];
// Loop over every location element on the DOM.
for (var j = 0; j < locationElements.length; j++) {
var children = locationElements[j].children;
// Initialize this location with the tour id; we'll pass in data...
var thisLocation = {
TourId: thisTour.getId()
};
// ... by looping over the DOM children and grabbing their form values.
for (var k = 0; k < children.length; k++) {
if (
children[k].classList.value.includes("stoptitle") &&
children[k].value
) {
var stopTitle = children[k].value;
thisLocation.title = stopTitle;
}
if (
children[k].classList.value.includes("stopaddress") &&
children[k].value
) {
var stopAddress = children[k].value;
thisLocation.address = stopAddress;
}
if (
children[k].classList.value.includes("stopdescription") &&
children[k].value
) {
var stopDescription = children[k].value;
thisLocation.description = stopDescription;
}
}
// Push this location into our locations array.
locations.push(thisLocation);
Finally, this is how the app/db are synced:
require("dotenv").config();
var express = require("express");
var session = require("express-session");
var exphbs = require("express-handlebars");
var helpers = require("./lib/helpers");
var db = require("./models");
var passport = require("./config/passport");
var app = express();
var PORT = process.env.PORT || 3000;
// Middleware
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static("public"));
var hbs = exphbs.create({
defaultLayout: "main",
helpers: helpers // Require our custom Handlebars helpers.
});
//Sessions are used to keep track of our user's login status
app.use(
session({ secret: "keyboard cat", resave: true, saveUninitialized: true })
);
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req, res, next) {
res.locals.user = req.user; // Set a local variable for our user.
next();
});
// Handlebars
app.engine("handlebars", hbs.engine);
app.set("view engine", "handlebars");
// Routes
require("./routes/apiRoutes")(app);
require("./routes/htmlRoutes")(app);
var syncOptions = { force: false };
// If running a test, set syncOptions.force to true
// clearing the `testdb`
if (process.env.NODE_ENV === "test") {
syncOptions.force = true;
}
// Starting the server, syncing our models ------------------------------------/
db.sequelize.sync(syncOptions).then(function() {
app.listen(PORT, function() {
console.log(
"==> 🌎 Listening on port %s. Visit http://localhost:%s/ in your browser.",
PORT,
PORT
);
});
});
module.exports = app;
I've been googling for four days....help!
Try adding this to your associations, also why are you defining twice the association function on Tour?
module.exports = function(sequelize, DataTypes) {
var Location = sequelize.define("Location", {
//
});
Location.associate = function(models) {
Location.belongsTo(models.Tour, { as:'Tour', foreignKey:'tourId', onDelete: "cascade"});
};
return Location;
};
module.exports = function(sequelize, DataTypes) {
var Tour = sequelize.define("Tour", {
//
});
Tour.associate = function(models) {
Tour.hasMany(models.Location, { as: 'Locations', foreignKey: 'tourId'});
Tour.belongsTo(models.User, { as: 'User', foreignKey: 'userId' });
};
return Tour;
};
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define("User", {
//
});
User.associate = function(models) {
User.hasMany(models.Tour, {as: 'Tours', foreignKey: 'userId'});
};
return User;
};
And add the same on the query.
db.Tour.findOne({
where: { id: req.params.id },
include: [{
model: db.Location,
as: 'Locations'
}]
}).then(function(tour) {
res.render("tour", {
tour: tour
});
});
I figured it out - the fact that I had defined the association on the tours model twice was breaking everything. Once I combined them as mentioned above, everything worked perfectly!
One other thing to note - sequelize automatically assigns the foreign key and the alias, so I left that part out.

AngularJS - using data from a service in a directive

I have set up a service to collect JSONP data from a server. If I use console.log to output 'data.d.results' in the service, I get a simple array object with six items.
However, when I do the same thing within the directive I get a much more complex object returned - one containing $$state, error, success, proto at the top level.
Because this is a more complex object, I can't figure out how to refer to the actual data that I'm after.
Can anybody tell me where I'm going wrong when passing the data or what I need to do to reference the data in the directive? When I go down the tree in the developer tools I find the actual data here:
d > $$state > value > data > d > results > [0-5] > CardID
My code is below:
app.directive('dashboardcard', ['DashboardCardService', function(DashboardCardService){
return{
restrict: 'E',
link: function($scope, element, atttributes){
$scope.data = DashboardCardService;
},
template: 'Card Name: {{CardID}}'
};
}]);
app.factory('DashboardCardService', ['$http', function($http){
var request = {
method: 'GET',
url: '/api.svc/tbl_Card/',
dataType: 'jsonp',
useDefaultXhrHeader: false,
headers: {'Content-type': 'application/json'},
headers: {'Accept': 'application/json;odata=light;q=1,application/json;odata=verbose;q=0.5'},
crossDomain: true
};
return $http(request).success(function(data) {
return data.d.results;
});
}]);
Thank you
One way to make it work with your current code and minimum changes would be something like that
app.directive('dashboardcard', ['DashboardCardService', function(DashboardCardService){
return{
restrict: 'E',
link: function($scope, element, atttributes){
DashboardCardService.success(function(data){
$scope.data = data
});
},
template: 'Card Name: {{CardID}}'
};
}]);
app.factory('DashboardCardService', ['$http', function($http){
var request = {
method: 'GET',
url: '/api.svc/tbl_Card/',
dataType: 'jsonp',
useDefaultXhrHeader: false,
headers: {'Content-type': 'application/json'},
headers: {'Accept': 'application/json;odata=light;q=1,application/json;odata=verbose;q=0.5'},
crossDomain: true
};
return $http(request)
}]);
or
app.directive('dashboardcard', ['DashboardCardService', function(DashboardCardService){
return{
restrict: 'E',
link: function($scope, element, atttributes){
$scope.dashboardService = DashboardCardService;
},
template: 'Card Name: {{dashboardService.data.CardID}}'
};
}]);
app.factory('DashboardCardService', ['$http', function($http){
var service = {};
var request = {
method: 'GET',
url: '/api.svc/tbl_Card/',
dataType: 'jsonp',
useDefaultXhrHeader: false,
headers: {'Content-type': 'application/json'},
headers: {'Accept': 'application/json;odata=light;q=1,application/json;odata=verbose;q=0.5'},
crossDomain: true
};
$http(request).success(function(data) {
service.data = data.d.results;
});
return service
}]);
You can also check my plunk that demonstrates several ways to put data into directive from service
http://plnkr.co/edit/YOzP2VCPOXwh4qoQC73i?p=preview

ExtJS ComboBox dynamic JSON updates

I have found numerous issues explaining why the JSON store is not updated in an Ext JS comboBox.
We have made a re-usable ExtJS combobox control, this is the source code for it.
Ext.define('ReusableComboBox', {
extend: 'Ext.form.field.ComboBox',
alias: 'widget.Reusablecombobox',
queryMode: 'local',
forceSelection: true,
valueField: 'id',
displayField: 'displayField',
autoLoad: false,
initComponent: function () {
if (!this.store) {
var store = Ext.create('Ext.data.Store', {
autoLoad: this.autoLoad,
fields:['id', 'displayField', 'Id', 'Code', 'Description', 'IsIncluded', 'IsActive'],
proxy: {
type: 'ajax',
url: urlContent('validurl/getcodes'),
reader: {
type: 'json',
root: 'data'
}
}
});
store.on('load', this.handler_StoreLoad, this);
Ext.apply(this, {
store: store
});
}
this.callParent();
},
handler_StoreLoad: function (store, records, successful, options) {
addFieldsToList(records, function (item) {
item.data['id'] = item.data.Id;
item.data['displayField'] = item.data.Code + ' | ' + item.data.Description;
});
},
addFieldsToList: function( list, buildDisplayFieldFunc ){
if( list ){
for( var i=0, j=list.length; i<j; i++ ){
buildDisplayFieldFunc( list[i] );
}
return list;
}
}
});
When I dynamically add another item to the comboBox store, the comboBox does not refresh. I have tried the following things.
The following tries comes up with blank elements in the comboBox
Call the removeAll(), clearValue() functions on the store and re-initialize using the bindStore(model), it comes up with empty list items.
comboBox.store.reload(model);
The following tries adds the new item as a blank element in the comboBox
var data = [];
data.push(new Ext.data.Record({id: options[0].Id, displayField : options[0].Code + ' | ' + options[0].Description}));
comboBox.store.add(data);
comboBox.store.loadData(data, true);
Has anyone seen and struggled with what I am talking about ?
Thanks in advance for your help.
I tried your code and it works with the below change and it is not required to call store.loadData
var data = []; data.push({id: options[0].Id, displayField : options[0].Code + ' | ' + options[0].Description});
comboBox.store.add(data);
What you have done is not the best way to map the returned JSON to your store,
I have modified your code for the mappings which is the best way to do and it doesn't require you to call the load listener and manually add the records.
Ext.define('ReusableComboBox', {
extend: 'Ext.form.field.ComboBox',
alias: 'widget.reusablecombobox',
queryMode: 'local',
forceSelection: true,
valueField: 'id',
displayField: 'displayField',
autoLoad: false,
initComponent: function () {
if (!this.store) {
var store = Ext.create('Ext.data.Store', {
autoLoad: this.autoLoad,
fields:[ 'Id', 'Code', 'Description', 'IsIncluded', 'IsActive',
{
name: 'displayField',
convert: function(v, record) {
return record.get('Code') + ' | ' + record.get('Description');
}
},
{name: 'id', mapping: 'Id'}
],
proxy: {
type: 'ajax',
url: urlContent('validurl/getcodes'),
reader: {
type: 'json',
root: 'data'
}
}
});
Ext.apply(this, {
store: store
});
}
this.callParent();
}});

How do get jquery fullcalendar to pass additional parameters to my json feed script

My code is as follows
jQuery('#calendar').fullCalendar({
weekMode: 'liquid',
events: themeforce.events,
eventRender: function (event, element) {
element.find('span.fc-event-title').html(element.find('span.fc-event-title').text());
}
});
where themeforce.events is a variable containing an encoded url of the json feed a php file - all works well.
I tried replacing events: themeforce.events, with
events: {
url: themeforce.events,
type: 'POST',
data: {
custom_param1: 'something',
custom_param2: 'somethingelse'
},
However now the calendar fails to load.
What can I do?
I wanted the start and end times for a post ajax request and it took me a bit of time to work it out.
This might help you:
events: function(start, end, timezone, callback) {
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
data: {
start: start.format(),
end: end.format(),
custom_param1: 'value 1',
custom_param2: 'value 2',
},
error: function () {
alert('there was an error while fetching events!');
},
success: function(doc) {
var events = [];
$.each(doc,function (index, e) {
events.push(e);
});
callback(events);
}
});
}
You should use extraParams as explained in doc : https://fullcalendar.io/docs/events-json-feed
var calendar = new Calendar(calendarEl, {
eventSources: [
// your event source
{
url: '/myfeed.php',
method: 'POST',
extraParams: {
custom_param1: 'something',
custom_param2: 'somethingelse'
},
failure: function() {
alert('there was an error while fetching events!');
},
color: 'yellow', // a non-ajax option
textColor: 'black' // a non-ajax option
}
// any other sources...
]
});
Also be sure your feed's url return raw json data array !
Just put "data" instead of "extraParams" in "events"
events: {
url: 'service.php',
method: 'POST',
data: {
custom_param1: 'something',
custom_param2: 'somethingelse'
},
failure: function() {
alert('there was an error while fetching events!');
},
}