Support Forum
Hi, i finally made it and created a page with two schedulers. It's a customer demand because he needs to have fixed events to drag onto the
main scheduler, etc. Business needs that i will no bore you with the explanations.
Now i have a problem, after both schedulers load all data stores, if i click on the filter (after changing dates, etc) button i get this error:
Line: 11
Error: 'this.config[...].width' is null or not an object
If i just leave the main scheduler everything is ok but this error only started to appear after adding the second schduler. I'm doing something wrong i know!
Any ideias!?
This is how i load the child scheduler:
what a mess!?!!?!? on top the child scheduler ant on the bottom the main scheduler.
main scheduler, etc. Business needs that i will no bore you with the explanations.
Now i have a problem, after both schedulers load all data stores, if i click on the filter (after changing dates, etc) button i get this error:
Line: 11
Error: 'this.config[...].width' is null or not an object
If i just leave the main scheduler everything is ok but this error only started to appear after adding the second schduler. I'm doing something wrong i know!
Any ideias!?
This is how i load the child scheduler:
var thisContext = this;
this.scheduler.on('afterrender', function () {
var schPnlRotations = thisContext.createRotationsScheduler();
var pnlRotationsScheduler = Ext.getCmp('pnlRotationsScheduler');
pnlRotationsScheduler.items.add(schPnlRotations);
});
...both schedulers have diferent id's, stores with diferent names, etc.
....this is where i insert the child scheduler...
{
width: '88%',
region: 'center',
layout: 'border',
border: true,
frame: true,
items: [
new Ext.Panel({
id: 'pnlRotationsScheduler',
border: false,
frame: false,
title: 'Rotations',
width: '100%',
region: 'north',
height: 140,
collapsible: true,
bodyStyle: 'padding:0px;margin:0px;',
margins: '0 0 0 0'
}),
//main scheduler
this.scheduler
]
},
- Attachments
-
- Capture.JPG (76.32 KiB) Viewed 8610 times
hi...here's the code...i'm sorry about the mess it is; it's because it's still work in progress and there's a lot of ambiguous things.
Ext.ns('App');
Ext.onReady(function () {
Ext.QuickTips.init();
<%ViewData["title"] = "Roster Plan";
ViewData["renderTo"] = "panel";
Html.RenderPartial("/Views/Shared/Menu.ascx");%>
App.init();
});
App = {
// Initialize application
init: function () {
var start = new Date();
start.clearTime();
start.setHours(24);
// show this week and the next four.
var beginDate = new Date();
var dow = beginDate.getDay();
beginDate = beginDate.add(Date.DAY, -dow);
var endDate = beginDate.add(Date.DAY, 4 * 7);
//this.scheduler.store.data.items[0].data.Group = 'dsdasdasd';
//Store CrewRanks
var crewRanksStore = new Ext.data.Store({
// TODO unhardcode this URL...
url: "/CrewRank/ListJson",
reader: new Ext.data.JsonReader({
root: 'rows',
totalProperty: 'total',
id: 'id',
fields: [
{ name: 'code' },
{ name: 'description' }
]
})
});
//Store aircraft Models
var aircraftModelsStore = new Ext.data.Store({
// TODO unhardcode this URL...
url: "/AircraftModels/ListJson",
reader: new Ext.data.JsonReader({
root: 'rows',
totalProperty: 'total',
id: 'id',
fields: [
{name: 'code'},
{name: 'name'},
{name: 'description'}
]
})
});
//Store crew Rank Groups
var crewRankGroupStore = new Ext.data.Store({
// TODO unhardcode this URL...
url: "/crewRankGroup/ListJson",
reader: new Ext.data.JsonReader({
root: 'rows',
totalProperty: 'total',
id: 'id',
fields: [
{name: 'id'},
{name: 'code'},
{name: 'name'}
]
})
});
//Store activities, the right side grid store containing all available activities
var storeActivities = new Ext.data.Store({
url: "/rpmdata/ListSchedulerActivitiesJson",
reader: new Ext.data.JsonReader({
root: 'rows',
totalProperty: 'total',
id: 'Id',
fields: [
{name: 'Id', type: 'string'},
{name: 'top', type: 'int'},
{name: 'resizeHandles', type:'boolean'},
{name: 'eventTypeId', type: 'int'},
{name: 'Title', type: 'string'},
{name: 'Description', type: 'string'},
{name: 'Duration', type: 'int'},
{name: 'Color', type: 'string'},
{name: 'ActivityId', type:'int' },
{name: 'RotationId', type:'int' }
]
}),
sortInfo: {field:'Title', direction:'ASC'},
remoteSort: true
});
// Store holding all the resources: CrewMembers rows and Rotations row
var resourceStore = new Ext.data.GroupingStore({
proxy: new Ext.data.HttpProxy({method: 'POST', url: '/rpmdata/ListSchedulerResources'}),
sortInfo: { field: 'Name', direction: "ASC" },
groupField: 'Group',
groupDir: 'DESC',
//idProperty: 'id',
baseParams: {start: 0, limit: 8},
reader: new Ext.data.JsonReader(
{idProperty: 'Id', root: 'rows', totalProperty: 'total'},
['Id', 'Group', 'Name', 'StartAvailability', 'EndAvailability']
)
});
//Loads all the events from CrewMembers
var eventStore = new Ext.data.Store({
url: "/rpmdata/ListSchedulerEvents",
reader: new Ext.data.JsonReader({
root: 'rows',
totalProperty: 'total',
id: 'Id',
fields: [
//be very precise about field types here, it can lead to stupid errors if you set them wrong.
{ name: 'Id', type: 'string' },
{ name: 'ResourceId', type: 'int' },
{ name: 'Duration', type: 'int' },
{ name: 'StartDate', type: 'date', dateFormat: 'Y-m-d G:i:s'},
{ name: 'EndDate', type: 'date', dateFormat: 'Y-m-d G:i:s'},
{ name: 'Title', type: 'string' },
{ name: 'Description', type: 'string' },
{ name: 'Color', type: 'string' },
{ name: 'eventTypeId', type: 'int' },
{ name: 'resizeHandles', type:'boolean' },
{ name: 'top', type: 'int' },
{ name: 'ActivityId', type:'int' },
{ name: 'RotationId', type:'int' },
{ name: 'RotationStartDate', type: 'date', dateFormat: 'Y-m-d G:i:s'},
{ name: 'RotationEndDate', type: 'date', dateFormat: 'Y-m-d G:i:s'},
{ name: 'Rotation'}
]
}),
sortInfo: {field:'Title', direction:'ASC'},
remoteSort: true
});
this.scheduler = this.createScheduler(resourceStore, eventStore);
this.unplannedTaskGrid = this.createTaskGrid(storeActivities);
this.scheduler.on('eventcontextmenu', this.onEventContextMenu, this);
var ctPanel = new Ext.Panel({
layout: 'border',
border: false,
height: 700,
width: '100%',
items: [
new Ext.FormPanel({
labelWidth: 125,
frame: true,
//title: 'Filter by date range',
bodyStyle: 'padding:5px 5px 0',
width: '100%',
defaults: { width: 175 },
region: 'north',
height: 130,
collapsible: true,
items: [
{
layout:'column',
border:true,
width:'100%',
items:[
{
columnWidth:.3,
layout: 'form',
border:true,
items: [
{
xtype: 'combo',
store: crewRanksStore,
valueField: 'code',
displayField: 'code',
name: 'rank',
id: 'crewRankField',
fieldLabel: 'Crew Rank',
typeAhead: true,
triggerAction: 'all',
selectOnFocus: true,
forceSelection: true
},
{
xtype: 'datefield',
fieldLabel: 'Begin Date',
name: 'beginDate',
id: 'beginDateField',
vtype: 'daterange',
endDateField: 'endDateField', // id of the end date field
format: 'Y-m-d',
value: beginDate.format('Y-m-d')
}
]
},
{
columnWidth:.3,
layout: 'form',
border:true,
items: [
{
xtype: 'combo',
store: crewRankGroupStore,
valueField: 'id',
displayField: 'name',
name: 'crewRankGroup',
id: 'crewRankGroupField',
fieldLabel: 'Crew Rank Group',
typeAhead: true,
triggerAction: 'all',
selectOnFocus: true,
forceSelection: true
},
{
xtype: 'datefield',
fieldLabel: 'End Date',
name: 'endDate',
id: 'endDateField',
startDateField: 'startDateField', // id of the start date field
format: 'Y-m-d',
value: endDate.format('Y-m-d')
}
]
},
{
columnWidth:.3,
layout: 'form',
border:true,
items: [
{
xtype: 'combo',
store: aircraftModelsStore,
valueField: 'code',
displayField: 'name',
name: 'aircraftModel',
id: 'aircraftField',
fieldLabel: 'Aircraft Model',
typeAhead: true,
triggerAction: 'all',
selectOnFocus: true,
forceSelection: true
}
]
}
]
}
],
buttonAlign: 'left',
buttons: [
{
text: 'Filter',
handler: function () {
var schPnlRosterPlan = Ext.getCmp('schPnlRosterPlan');
var schPnlRotations = Ext.getCmp('schPnlRotations');
var crewRankCode = Ext.getCmp('crewRankField').getValue();
var RankGroupId = Ext.getCmp('crewRankGroupField').getValue();
var beginDateField = Ext.getCmp('beginDateField').getValue();
var endDateField = Ext.getCmp('endDateField').getValue();
endDateField = endDateField.add(Date.DAY, 1);
//load resources (crewmembers rows & rotation row)
resourceStore.load({
params: {rankCode: crewRankCode, RankGroupId: RankGroupId},
callback:function(records, options, success) {
var arrResources = getResources(records);
//load all events; crewmember events & rotations events
eventStore.load({
params: {arrResourcedId: arrResources, rankCode: crewRankCode, rankGroupCode: null, beginAtTime: beginDateField, endAtTime: endDateField},
callback:function(records, options, success) {
schPnlRosterPlan.setView(beginDateField, endDateField, 'day', Sch.ViewBehaviour.DayView);
schPnlRotations.setView(beginDateField, endDateField, 'day', Sch.ViewBehaviour.DayView);
}
});
}
});
}
}
]
}),
//the main scheduler
{
width: '88%',
region: 'center',
layout: 'border',
border: true,
frame: true,
items: [
new Ext.Panel({
id: 'pnlRotationsScheduler',
border: false,
frame: false,
title: 'Rotations',
width: '100%',
region: 'north',
height: 140,
collapsible: true,
bodyStyle: 'padding:0px;margin:0px;',
margins: '0 0 0 0'
}),
//add tasks grid
this.scheduler
]
},
{
width: '12%',
region: 'east',
layout: 'border',
border: true,
frame: true,
collapsible: true,
resizable: true,
items: [
//add tasks grid
this.unplannedTaskGrid
]
}
]
});
storeActivities.load({
callback:function(records, options, success) {
//For some odd reason we get a js error if we load the Scheduler before the events grid.
ctPanel.render(Ext.getBody());
}
});
var thisContext = this;
this.scheduler.on('afterrender', function () {
var schPnlRotations = thisContext.createRotationsScheduler();
var pnlRotationsScheduler = Ext.getCmp('pnlRotationsScheduler');
pnlRotationsScheduler.items.add(schPnlRotations);
});
ctPanel.on('afterrender', function () {
initializeTaskDragZone(this.unplannedTaskGrid, this.scheduler.id);
Ext.getCmp('crewRankField').setValue("CPT");//default filter
//load resources (crewmembers rows & rotation row)
resourceStore.load({
params: {rankCode: Ext.getCmp('crewRankField').getValue("CPT"), RankGroupId: null},
callback:function(records, options, success) {
var arrResources = getResources(records);
//load all events; crewmember events & rotations events
eventStore.load({
params: {arrResourcedId: arrResources, rankCode: 'CPT', rankGroupCode: null, beginAtTime: beginDate, endAtTime: endDate},
callback:function(records, options, success) {
}
});
}
});
}, this);
},
//Create the Activities Grid
createTaskGrid: function (storeActivities) {
var rendererEvent = function (value, row, record)
{
return '<div style="margin-right:4px;width:14px;height:14px;float:left;background-color:' +
record.data.Color + ';"> </div><span>' + value + '</span>';
}
return new Ext.grid.GridPanel({
id: 'gridTasks',
store: storeActivities,
stripeRows: true,
border: false,
region:'center',
//cls: 'taskgrid',
loadMask: true,
columns: [
{ header: 'Tasks', sortable: false, width: '40%', dataIndex: 'Title', renderer: rendererEvent }
],
selModel: new Ext.grid.RowSelectionModel({singleSelect:true})
});
},
//Context Menu
onEventContextMenu: function (g, rec, e) {
e.stopEvent();
//prevents from showing context menu if event is of type Rotation
if (rec.data.ResourceId == -1) {//Rotations row
return false;
}
if (!g.gCtx) {
g.gCtx = new Ext.menu.Menu({
items: [
{
id: 'context-delete',
text: 'Delete event',
iconCls: 'icon-delete'
},
{
id: 'context-lock',
text: 'Lock event',
iconCls: 'icon-lock'
}
]
});
g.gCtx.on('itemclick', function (item, e) {
switch (item.id) {
case 'context-delete':
g.eventStore.remove(g.gCtx.rec);
break;
default:
alert(item.id + ' is not a valid menu action');
break;
}
}, this);
};
g.gCtx.rec = rec;
g.gCtx.showAt(e.getXY());
},
//Event style afer being dropped onto the scheduler
eventRenderer: function (event, r, row, col, ds) {
var eventTypeId = event.data ? event.data.eventTypeId : event.json.eventTypeId;
var resizeHandles = event.data ? event.data.resizeHandles : event.json.resizeHandles;
//alert('renderer: ' + event.get('Id'));
return {
Id: event.get('Id'),
ResourceId: event.get('ResourceId'),
//Duration
//StartDate
//EndDate
//Title
Description: event.get('Description'),
//Color
eventTypeId: eventTypeId,
resizeHandles: resizeHandles,
top: event.get('top'),
ActivityId: event.get('ActivityId'),
RotationId: event.get('RotationId'),
RotationStartDate: event.get('RotationStartDate'),
RotationEndDate: event.get('RotationEndDate'),
//TODO: create object of type Rotation
Rotation: event.get('Rotation'),
cls: event.get('Color'),
text: event.get('Title')
};
},
//TODO: remove this? unused renderer?
rendererRow: function (event, r, row, col, ds) {
},
// This function adds some background styling to the scheduling cells
timeCellRenderer : function (events, m, resourceRecord, row, col, ds, cellStartTime, cellEndTime, grid) {
/*var cellStartHours = cellStartTime.getHours();
cellEndHours = cellEndTime.getHours();
if (cellStartHours < resourceRecord.get('StartAvailability') ||
cellStartHours > resourceRecord.get('EndAvailability')) {
//m.css = 'unavailable';
}*/
m.css = cellStartTime.getDay()%6==0 ? 'highlightWeekends' : '';
},
createScheduler: function (resourceStore, eventStore) {
// show this week and the next four.
var beginDate = new Date();
var dow = beginDate.getDay();
beginDate = beginDate.add(Date.DAY, -dow);
var endDate = beginDate.add(Date.DAY, 4 * 7);
/*var start = new Date();
start.clearTime();
start.setHours(0);
var end = start.clone();
end.setHours(24);*/
var start = beginDate; // new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());
var end = endDate; // start.add(Date.DAY, 30);
// Date line functionality
var datelineStore = new Ext.data.JsonStore({
autoDestroy: true,
fields: [
'Text',
{ name: 'Date', type: 'date' }
],
data: [{
Text: 'Today',
Date: new Date()
}]
});
/*var task = {
run: function () {
datelineStore.getAt(0).set('Date', new Date());
},
interval: 10000 // Update line store every 10 seconds
};
var runner = new Ext.util.TaskRunner();
runner.start(task);*/
var crewMemberTemplate = new Ext.XTemplate(
'<span>{Name}</span>'
);
var rotationTemplate = new Ext.XTemplate(
'<div> </div>'
);
var g = new Sch.SchedulerPanel({
id: 'schPnlRosterPlan',
//Look and feel, basic settings
resizeHandles: 'both',
enableDragCreation: false,
region: 'center',
enabledHdMenu: false,
stripeRows: true,
border: true,
trackMouseOver: true,
loadMask : true,
allowOverlap: false,
highlightWeekends: true,
showTodayLine: true,
maskDisabled: false,
colModel: new Ext.ux.grid.LockingColumnModel({
columns: [
{ header: 'Staff', sortable: true, width: 150, dataIndex: 'Name', locked: true,
renderer: function (v, m, r) {
if (r.id == -1) {//rotations row
return rotationTemplate.apply(r.data);
} else {
return crewMemberTemplate.apply(r.data);
}
}
},
{ header: 'Type', sortable: true, width: 150, dataIndex: 'Group', locked: true, hidden: true }
]
}),
view: new Sch.LockingGroupingSchedulerView({
forceFit: false,
showGroupName: false,
//emptyGroupText: 'Rotations',
resizable: true
}),
// Timline view configuration
viewModel: {
start: start,
end: end,
columnType: 'day',
viewBehaviour: Sch.ViewBehaviour.DayView
},
viewConfig: { forceFit: true },
//This is the event renderer. It renders the event after being dropped onto the scheduler.
//The fields referenced between {} are the ones defined in eventRenderer
eventTemplate: new Ext.XTemplate(
'<div id="{id}" style="top:{top}px;width:{width}px;left:{leftOffset}px" class="sch-event {cls}">' +
'<div class="{[values.resizeHandles ? "x-resizable-handle x-resizable-handle-west" : ""]}"></div>',
'<div class="sch-event-inner">' +
'<span class="sch-event-header">{[values.text]}</span>' +
'</div>' +
'<div class="{[values.resizeHandles ? "x-resizable-handle x-resizable-handle-east" : ""]}"></div>',
'</div>'
).compile(),
//TODO: review these css classes
tooltipTpl : new Ext.XTemplate(
'<dl class="eventTip">',
'<dt class="icon-task"></dt><dd><b>{Title}</b>{[values.Description ? ( values.eventTypeId == 2 ? "" : (" (" + values.Description + ")")) : ""]}</dd>',
'<dt class="icon-clock">Start: </dt><dd>{[values.StartDate.format("Y-m-d G:i")]}</dd>',
'<dt class="icon-clock">End: </dt><dd>{[values.EndDate.format("Y-m-d G:i")]}</dd>',
'</dl>').compile(),
timeCellRenderer : this.timeCellRenderer,
eventRenderer: this.eventRenderer,
store: resourceStore,
eventStore: eventStore,
//drag and drop validation event
dndValidatorFn: function (dragEventRecords, targetRowRecord, b, c, e) {
window.status = 'dndValidatorFn: ' + targetRowRecord.get('Group') +
', eventTypeId: ' + dragEventRecords[0].get('eventTypeId') +
', ResourceId: ' + dragEventRecords[0].get('ResourceId');
//Makes the rotation go back to top position 0 when inside the scheduler, after beiing dropped
if (dragEventRecords[0].get('eventTypeId') == 2) {//Rotation
dragEventRecords[0].data.top = 0;
}
//Avoid inserting events of type Activity in the Rotations row
if (dragEventRecords[0].get('eventTypeId') == 1//Activity
&& targetRowRecord.get('Group') == "Rotations") {
return false;
}
/*alert(
'a: ' + targetRowRecord.get('Group') + '\n\n' +
//'b: ' + dragEventRecords[0].get('Group') + '\n\n' +
'c: ' + dragEventRecords[0].get('eventTypeId')
//'d: ' + targetRowRecord.get('eventTypeId')
);*/
// Only allow drops on the same row
//return dragEventRecords[0].get('ResourceId') === targetRowRecord.get('Id');
},
tbar: [
{
iconCls: 'icon-prev',
handler: function () {
g.setView(g.getStart().add(Date.MONTH, -1), g.getEnd().add(Date.MONTH, -1));
}
},
{
text: 'Days',
handler: function () {
var s = g.getStart(),
e = s.add(Date.DAY, 31);
g.setView(s, e, 'day', Sch.ViewBehaviour.DayView);
}
},
{
text: 'Hours and days',
handler: function () {
var s = g.getStart();
s.clearTime();
s.setHours(0);
var e = s.add(Date.HOUR, 24);
g.setView(s, e, 'hourAndDay', Sch.ViewBehaviour.HourView);
}
},
{
text: 'Months',
handler: function () {
var s = g.getStart(),
e = s.add(Date.MONTH, 12);
g.setView(s, e, 'month', Sch.ViewBehaviour.MonthView);
}
},
'->',
{
iconCls: 'icon-next',
handler: function () {
g.setView(g.getStart().add(Date.MONTH, 1), g.getEnd().add(Date.MONTH, 1));
}
}
],
// paging bar on the bottom
/*bbar: new Ext.PagingToolbar({
pageSize: 8,
store: resourceStore,
displayInfo: true,
displayMsg: 'Displaying tasks {0} - {1} of {2}',
emptyMsg: "No tasks to display"
}),*/
//resize event, limit event resizing or save event
resizeValidatorFn: function (resourceRecord, eventRecord, start, end) {
//return Date.getDurationInDays(start, end) <= 3;
/*if (resourceRecord.id = 'rotationsRow') {
return false;
}*/
},
//Scheduler event listeners
listeners: {
beforeTooltipShow : function(scheduler, record) {
if (scheduler.gCtx) {
return scheduler.gCtx.isVisible() ? false : true;
}
},
//Event Drop: happens when the user drops any event on the scheduler
drop: function (scheduler, records, copy, valid) {
window.status =
'Id = ' + records[0].data.Id + ' ,' +
'ResourceId = ' + records[0].data.ResourceId + ' ,' +
//'Duration = ' + records[0].data.Duration + ' ,' +
//'RotationStartDate = ' + records[0].data.RotationStartDate.format("Y-m-d G:i:s") + ' ,' +
//'RotationEndDate = ' + records[0].data.RotationEndDate.format("Y-m-d G:i:s") + ' ,' +
//'Title = ' + records[0].data.Title + ' ,' +
//'Description = ' + records[0].data.Description + ' ,' +
//'Color = ' + records[0].data.Color + ' ,' +
'eventTypeId = ' + records[0].data.eventTypeId + ' ,' +
//'resizeHandles = ' + records[0].data.resizeHandles + ' ,' +
'top = ' + records[0].data.top + ' ,';//+
//'ActivityId = ' + records[0].data.ActivityId + ' ,' +
//'RotationId = ' + records[0].data.RotationId;
var record = records[0];
var resourceId = scheduler.store.getAt(24).id,
viewStart = scheduler.getStart(),
viewEnd = scheduler.getEnd();
var rowEvents = scheduler.eventStore.queryBy(function(ev) {
return ev.get('ResourceId') === resourceId &&
Date.intersectSpans(ev.get('StartDate'), ev.get('EndDate'), viewStart, viewEnd); });
//verify if there is no rotation event being dropped on a activity event
//we must check this because rotations can be dropped far from it's target and still
//go back to it's correct position, this position might have an event. we must check this.
//TODO: review this!!!
/*var r = g.eventStore.query("ResourceId", record.data.ResourceId);
Ext.each(r.items, function (event) {
var event = event.data;
var rec = record.data;
if(rec.ResourceId == event.ResourceId && event.eventTypeId == 2){
if(event.StartDate >= rec.StartDate
//&& (event.EndDate < rec.EndDate || event.EndDate > rec.EndDate)
){
return false;
}
}
});*/
//Rotations only, if event being dropped is of type Rotation
if(record.data.eventTypeId == 2 //rotations
&& record.data.RotationId != null){
//Rotations only, this basically mekes the rotation stay allways in the same
//start and end date, while the user can only change the resource.
var rotations = g.eventStore.query("RotationId", records[0].data.RotationId);
Ext.each(rotations.items, function (rot) {
if(records[0].data.Id == rot.data.Id){
g.eventStore.remove([rot]);
rot.data.StartDate = rot.data.RotationStartDate;
rot.data.EndDate = rot.data.RotationEndDate;
rot.json.StartDate = rot.data.RotationStartDate;
rot.json.EndDate = rot.data.RotationEndDate;
//if the user is dropping on the rotations row we must restore top value.
//TODO: calculate if there is overlapping of rotations and adjust
//the top value accordingly
if(record.data.ResourceId == -1){
rot.json.top = 22;
rot.data.top = 22;
}
g.eventStore.add([rot]);
}
})
}
//Whenever a Activity is dropped onto the scheduler, we must add it's data to
//the scheduler's store. We basically copy the record from the activities grid store.
if (g.eventStore.indexOf(record) < 0) {
g.eventStore.add([record.copy()]);
//TODO: remove this in the future
//record.store.remove(record);//we keep the ativity on the grid.
}
},
//View Change, wher the user changes the date interval(view) on the scheduler
viewChange: function (view) {
window.status = 'Viewing events from ' + view.viewModel.start + ' to ' + view.viewModel.end;
},
//When the user clicks on an event
eventclick: function (scheduler, event, c, d) {
window.status = 'eventclick: ' + event.data.StartDate + " » " + event.data.EndDate;
},
eventdblclick: this.editEvent,
celldblclick: function (scheduler, rowIndex, cellIndex, e) {
if(cellIndex == 0){
var crewMemberId = scheduler.store.data.items[rowIndex].data.Id;
window.status = 'crewMemberId: ' + crewMemberId;
if(crewMemberId != -1){//rotations row
var crewRankCode = Ext.getCmp('crewRankField').getValue();
var RankGroupId = Ext.getCmp('crewRankGroupField').getValue();
var beginDateField = Ext.getCmp('beginDateField').getValue();
var endDateField = Ext.getCmp('endDateField').getValue();
resourceStore.load({
params: {crewMemberId: crewMemberId, rankCode: crewRankCode, RankGroupId: RankGroupId},
callback:function(records, options, success) {
}
});
}
}
},
//this event is fired where the user clicks on a resource row
//then the user will only see the resource he clicked
rowdblclick: function (scheduler, rowIndex, keys) {
}
},
plugins: [
//vertical timeline that show at what itme of the we are
new Sch.plugins.Lines({
store: datelineStore
})
]
});
return g;
},
createRotationsScheduler : function() {
// Store holding all the resources
var storeRotationRow = new Ext.data.GroupingStore({
sortInfo:{field: 'Name', direction: "ASC"},
groupField : 'Group',
idProperty : 'Id',
data : [
{Id : 'r1', Group : 'Sales', Name : '', StartAvailability : 0, EndAvailability : 24}
],
reader : new Ext.data.JsonReader({
idProperty : 'Id'
}, [
'Id',
'Group',
'Name',
'StartAvailability',
'EndAvailability'
]
)
});
// Store holding all the tasks
var storeRotationsEvents = new Ext.data.JsonStore({
sortInfo:{field: 'ResourceId', direction: "ASC"},
idProperty : 'Id',
fields : [
{name: 'Id', type:'string'},
{name: 'ResourceId'},
{name: 'StartDate', type : 'date'},
{name: 'EndDate', type : 'date'},
{name: 'Title'}
]
});
// show this week and the next four.
var beginDate = new Date();
var dow = beginDate.getDay();
beginDate = beginDate.add(Date.DAY, -dow);
var endDate = beginDate.add(Date.DAY, 4 * 7);
var start = beginDate; // new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());
var end = endDate; // start.add(Date.DAY, 30);
var schPnlRotations = new Sch.SchedulerPanel({
resizeHandles : 'none',
enableDragCreation : false,
id: 'schPnlRotations',
height : 100,
width : '100%',
stripeRows : true,
enabledHdMenu : false,
border : true,
store: storeRotationRow,
eventStore : storeRotationsEvents,
trackMouseOver : false,
colModel: new Ext.ux.grid.LockingColumnModel({
columns: [
{ header: 'Staff', sortable: true, width: 150, dataIndex: 'Name', locked: true}
]
}),
//view: new Sch.LockingSchedulerView({
//view: new Sch.LockingGroupingSchedulerView({
view: new Sch.LockingSchedulerView({
forceFit: false,
//showGroupName: false,
//emptyGroupText: 'Rotations',
resizable: true
}),
// Timline view configuration
viewModel: {
start: start,
end: end,
columnType: 'day',
viewBehaviour: Sch.ViewBehaviour.DayView
},
viewConfig: { forceFit: true }
});
return schPnlRotations;
},
editEvent: function (scheduler, event, c, d) {
window.status = 'eventdblclick: ' + event.data.StartDate + " » " + event.data.EndDate;
var activityStartTime = event.data.StartDate.format('G:i');
var activityEndTime = event.data.EndDate.format('G:i');
var activityStartDate = event.data.StartDate.format('Y-m-d');
var activityEndDate = event.data.EndDate.format('Y-m-d');
var windowEditEvent = new Ext.Window({
title:"Edit Activity " + event.data.Title + ", Id: " + event.data.Id,
id:'windowEditEvent',
layout:'fit',
width: 500,
height:160,
minWidth:500,
minHeight:160,
modal: true,
bodyStyle:'padding:5px 5px 0;',
buttonAlign:'center',
//autoHeight: true,
plain: true,
closeAction:'close',
items: [{
layout:'column',
bodyStyle:'background-color:#c7d6e9;border-color:#c7d6e9;',
items:[{
columnWidth:.5,
bodyStyle:'background-color:#c7d6e9;border-color:#c7d6e9;',
layout: 'form',
items: [{
id: 'beginTime',
xtype: 'timefield',
name: 'departureTime',
format: 'H:i',
fieldLabel: 'Start Time',
value:activityStartTime,
width: 100
}, {
xtype: 'datefield',
name: 'beginDateAct',
id: 'beginDateAct',
vtype: 'daterange',
endDateField: 'endDateField', // id of the end date field
format: 'Y-m-d',
value: activityStartDate,
width: 100,
fieldLabel: 'Start Date'
}]
},{
columnWidth:.5,
layout: 'form',
bodyStyle:'background-color:#c7d6e9;border-color:#c7d6e9;',
items: [{
id: 'endTime',
xtype: 'timefield',
name: 'departureTime1',
format: 'H:i',
fieldLabel: 'End Time',
bodyStyle: 'padding: 0 50px 0 0',
value:activityEndTime,
width: 100
},{
xtype: 'datefield',
name: 'endDateAct',
id: 'endDateAct',
vtype: 'daterange',
endDateField: 'endDateField', // id of the end date field
format: 'Y-m-d',
width: 100,
value: activityEndDate,
fieldLabel: 'End Date'
}]
}]
}],
buttons: [{
text: "Confirm",
handler: function() {
//old: url: "/RosterPlan/SaveCrewMemberEvent",
//int Type, string BeginAtTime, string EndAtTime, int CrewMemberId, int RotationId, int ActivityId
var params = {
Id: event.data.Id,
Type: 3,
BeginDate: Ext.getCmp('beginDateAct').getValue(),
BeginTime: Ext.getCmp('beginTime').getValue(),
EndDate: Ext.getCmp('endDateAct').getValue(),
EndTime: Ext.getCmp('endTime').getValue(),
CrewMemberId: event.data.ResourceId,
RotationId: null,
ActivityId: event.data.ActivityId
};
Ext.Ajax.request({
url: '/rpmdata/SaveSchedulerEvent',
//url: "/RosterPlan/SaveCrewMemberEvent",
success: function(form, action) {
},
failure: function(response, options) {
Ext.Msg.show({
title: 'Error',
msg: 'An error as occurred.',
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
},
params: params
});
/*beginTime = Ext.getCmp('beginTime').value;
endTime = Ext.getCmp('endTime').value;
beginDateAct = Ext.getCmp('beginDateAct').value;
endDateAct = Ext.getCmp('endDateAct').value;*/
//self.fireEvent("confirm",rosterPlanView, event,beginTime,endTime,beginDateAct,endDateAct);
windowEditEvent.close();
return;
}
}, {
text: "Cancel",
handler: function() {
windowEditEvent.close();
}
}]
});
windowEditEvent.show(false, function() {
windowEditEvent.center();
});
},
};
function initializeTaskDragZone(g, ddGroup) {
g.dragZone = new Ext.dd.DragZone(g.getEl(), {
ddGroup: ddGroup,
getDragData: function (e) {
var sourceEl = e.getTarget(),
rec = g.store.getAt(g.view.findRowIndex(sourceEl));
if (sourceEl && rec) {
var d = sourceEl.cloneNode(true);
d.id = Ext.id();
var wrap = Ext.get(Ext.DomHelper.createDom({
tag: 'div',
style: {
width: '200px'
},
children: [
{
tag: 'span',
cls: 'sch-dd-newtime',
html: ' '
}
]
}));
wrap.appendChild(d);
//Ext.fly(d).addClass('sch-event');
Ext.fly(d).update(rec.get('Title'));
Ext.fly(d).addClass(rec.get('Color'));
//Look and feel of an event while being dragged onto the Scheduler (events grid only)
return {
sourceEl: sourceEl,
repairXY: Ext.fly(sourceEl).getXY(),
duration: 1440, //rec.get('Duration') * 60,
ddel: wrap.dom,
sourceEventRecord: rec,
records: [rec]
};
}
},
//Provide coordinates for the proxy to slide back to on failed drag.
//This is the original XY coordinates of the draggable element.
getRepairXY: function () {
return this.dragData.repairXY;
}
});
}
//get all resources id's from store (crewmember id's)
function getResources(store){
var arrResourcedId = new Array();
Ext.each(store, function (res) {
if(res.id != "rotationsRow"){
arrResourcedId.push(res.id);
}
});
return arrResourcedId;
}
var nextId = function () {
// if the time isn't unique enough, the addition
// of random chars should be
var t = String(new Date().getTime()).substr(4);
var s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
for (var i = 0; i < 4; i++) {
t += s.charAt(Math.floor(Math.random() * 26));
}
return 'e' + t;
};
Ext.override(Ext.data.GroupingStore, {
groupDir : 'ASC',
groupBy : function(field, forceRegroup, direction){
direction = direction ? (String(direction).toUpperCase() == 'DESC' ? 'DESC' : 'ASC') : this.groupDir;
if(this.groupField == field && this.groupDir == direction && !forceRegroup){
return;
}
this.groupField = field;
this.groupDir = direction;
if(this.remoteGroup){
if(!this.baseParams){
this.baseParams = {};
}
this.baseParams['groupBy'] = field;
this.baseParams['groupDir'] = direction;
}
if(this.groupOnSort){
this.sort(field, direction);
return;
}
if(this.remoteGroup){
this.reload();
}else{
var si = this.sortInfo || {};
if(si.field != field || si.direction != direction){
this.applySort();
}else{
this.sortData(field, direction);
}
this.fireEvent('datachanged', this);
}
},
applySort : function(){
Ext.data.GroupingStore.superclass.applySort.call(this);
if(!this.groupOnSort && !this.remoteGroup){
if(this.groupField != this.sortInfo.field || this.groupDir != this.sortInfo.direction){
this.sortData(this.groupField, this.groupDir);
}
}
},
applyGrouping : function(alwaysFireChange){
if(this.groupField !== false){
this.groupBy(this.groupField, true, this.groupDir);
return true;
}else{
if(alwaysFireChange === true){
this.fireEvent('datachanged', this);
}
return false;
}
}
});
</script>
It's somewhat messy yes . Let's try to clean it up, it seems that you're overnesting a bit, using containgin Panels when there's no need to. Replace:
with just
and move the config properties below to the instantiation of the "this.scheduler" instance. Remember, the SchedulerPanel _is_ a panel. No need to put it inside a parent panel.
{
width: '88%',
region: 'center',
layout: 'border',
border: true,
frame: true,
items: [
new Ext.Panel({
id: 'pnlRotationsScheduler',
border: false,
frame: false,
title: 'Rotations',
width: '100%',
region: 'north',
height: 140,
collapsible: true,
bodyStyle: 'padding:0px;margin:0px;',
margins: '0 0 0 0'
}),
//add tasks grid
this.scheduler
]
},
this.scheduler
region: 'center',
border: true
Hi, i understand what you said about the scheduler itself being a panel, etc but, i need to mantain this layout. Customer demand.
If i do what you said i can no longer mantain the layout and i still keep on having the same error. Just tried it out 5 minutes ago.
The error: "Line: 11
Error: 'this.config[...].width' is null or not an object"
If i just mantain the main scheduler everything is ok.
If i do what you said i can no longer mantain the layout and i still keep on having the same error. Just tried it out 5 minutes ago.
The error: "Line: 11
Error: 'this.config[...].width' is null or not an object"
If i just mantain the main scheduler everything is ok.
Hi, thanks for all the quick replies. I think i got it now except for one thing, when i invoque this:
I get this error:
I think is something about the view. If i change 'day' to 'month' it works ok.
Any ideias!?
schPnlRosterPlan.setView(beginDateField, endDateField, 'day', Sch.ViewBehaviour.DayView);
"schPnlRosterPlan" is the main Scheduler.Line: 11
Error: 'this.config[...].width' is null or not an object
I think is something about the view. If i change 'day' to 'month' it works ok.
Any ideias!?