Select multiple time slots on click - fullcalendar

When I click on a empty time slot on fullCalendar, it draws a rectangle on that empty cell. So, If my slotDuration is 30min, the block represents 30 min. I also can drag the cursor over multiple cells and select a custom range. But what I need to do is, when the user click (not drag) on a cell, select and draw the rectangle on 2 cells (representing 1 hour). Is this possible? I cannot change the slotDuration.
If I change the snapDuration to 1 hour, it works, but sadly, I cannot change it also.
What I was looking for is a way to override the event.end but that did not work.
Update 1:
I was able to do this exposing the cellDuration property:
on fullCalendar.js:
t.setCellDuration = function (minutes) {
var duration = moment.duration(minutes, 'minutes');
var view = t.getView();
view.timeGrid.cellDuration = duration;
}
now on the renderEvent handler, I can call
element.fullCalendar("setCellDuration", 60);
It works but if there is an alternative that does not involve change fullCalendar code, it would be nice.

I think you cannot do it just modifying the properties of the calendar, but you could do it modifying the fullCalendar.js file. Yes, I know you specify it on your question, but I think there is not alternative.
Exactly the listenStop function, which resides at line 4527 at version 2.3.3
listenStop check an array call dates
dates[
{FCMoment}, //start
{FCMoment} //end
]
So, before that check, you can modify your end time as you prefer. In addition, you have to render it.
In your code, now listenStop() function should be something like:
listenStop: function(ev) {
if (dates) { // started and ended on a cell?
if (dates[0].isSame(dates[1])) {
dates[1] = dates[0].clone().add(1, 'hours'); //Now we modify the end
_this.renderSelection(dates[0], dates[1]); //And render the modified selection
view.trigger('dayClick', dayEl[0], start, ev);
}
if (isSelectable) {
// the selection will already have been rendered. just report it
view.reportSelection(start, end, ev);
}
}
}

Related

Showing progress window while creating other window/widgets

I have a function that looks like the following
void MainWindow::CreateEnvironment()
{
MdiWindow* sub = createSubWindow();
MyQTWidget* widget = CreateWidget();
..
..
}
I want that during this function a progress bar will be shown at the beggining and will close at the end of this function.
However adding
void MainWindow::CreateEnvironment()
{
**progressBarDialog->show();**
MdiWindow* sub = createSubWindow();
MyQTWidget* widget = CreateWidget();
..
..
**progressBarDialog->hide();**
}
Does not work, maybe because the function needs to exit first or something.
What is the best way to do this?
I assume that you use QProgressDialog?
You need to first setup the dialog with the correct number of steps you expect, how long you want to wait before it actually shows and more importantly: you need to call setValue() to update the progress bar.
Here is an example of how I would solve that (as far as I understand it)
void MainWindow::CreateEnvironment()
{
auto bar = new QProgressBarDialog(this);
bar->setLabelText(tr("Creating Environment..."));
bar->setCancelButton(nullptr); // No cancel button
bar->setRange(0, 10); // Let's say you have 10 steps
bar->setMinimumDuration(100); // If it takes more than 0.1 sec -> show the dialog
bar->setValue(0);
MdiWindow* sub = createSubWindow();
bar->setValue(1);
MyQTWidget* widget = CreateWidget();
..
..
bar->setValue(10);
MyLastWidget* last = CreateLastWidget();
bar->deleteLater(); // Not needed anymore, let's get rid of it
}
And don't worry too much if the dialog never shows. Unless you're doing really heavy computation (such as allocating / initialising huge portion of memory), creating widgets is very fast and would finish before the 100ms times out.
EDIT: Another thing to be aware of: QProgressDialog is meant to work after the main event loop started. (That is after the call to app.exec() in your main())
If you plan to show call this function in the constructor of your MainWindow, the dialog might even never show up because the window itself is not fully created and operational.
If you intended to call this function later, when the main window is already displayed on screen and the user hit a New Document button of some sort: you can ignore this part of the answer.

How to write if statement comparing numbers that creates objects conditionally in QML

I'm working with QML and Python3.6 + PySide2 and I'm trying to write script in QML that takes two integers from a connection in python and compares them to decide what image background to use for the window.
There are a few things I'm struggling with. First, I am unsure how to compare my numeric (sunset and sunrise) variables. Second, I don't know how to write an if statement-esque part that produces a background image conditionally. Third, I don't think it's best to do this under Connections, and maybe even in my QML, but I'm not sure how to move my variables somewhere else.
I really appreciate any pointers or help!!
The data I'm drawing from looks like this:
"sunrise":1592565499,"sunset":1592617094
The QML pseudo-ish code:
Connections {
target: weather
function onDataChanged(){
if(!weather.hasError()){
var sunrise = weather.data['dt']['sunrise']
var sunset = weather.data['dt']['sunset']
if (sunrise <= sunset)
Image {
source: "night.png"}
else
Image {
course: "day.png"}
}
You cannot create QML-items from if-statements like that (neither from State's). You can call Qt.createComponent if you like, however, it is rather overkill in this example. You should directly set the source property of your image:
Image {
id: image_tod
}
Connections {
target: weather
function onDataChanged(){
if(!weather.hasError()){
var sunrise = weather.data['dt']['sunrise']
var sunset = weather.data['dt']['sunset']
if (sunrise <= sunset)
image_tod.source = "night.png"
else
image_tod.source = "day.png"
}
}
}
Looking at the code, you might actually be able to bind it directly to the source property (not sure what your model exactly looks like):
Image {
source: {
if(weather.data['dt']['sunrise'] <= weather.data['dt']['sunset'])
return "night.png"
else
return "day.png"
}
}
This works because when compiling the QML, the engine creates a dependency from every referenced variable (weather and data in this case), and re-evaluates the whole binding if any of them signals a change. To make fully use of this, you should also expose hasError as a property rather than a function (and emit whenever it changes).
Follow-up update
Yes, you can make it as wild as you want. I think you mean this:
Image {
source: {
if(weather.data['dt']['sunrise'] <= weather.data['dt']['sunset'])
return "night.png"
else if(weather.data['dt']['sunrise'] > weather.data['dt']['sunset'])
return "day.png"
else
return "" //means no image
}
}

How to fix Maximum call stack size exceeded error in appmaker

I'm currently validating a date box widget to prevent filing after a 30 days grace period. The date validation was working but after the alert prompted it wasn't going down(I was stock in here even after a couple of clicks). Also the date box is not going null.
function checkDateValidate(widget) {
var form = app.pages.Newitem.descendants;
var otdate = form.otDateBox.value;
var date = new Date();
var pastdate = date.setDate(date.getDate() - 31);
if(otdate <= pastdate) {
alert('Date exceeds within 30 days grace period is invalid.');
form.otDateBox.value = null;
}
}
I expected to clear the date box widget.
This error sometimes happens because there is an infinite loop going on and this is your case. It is very important that you understand the difference between the onValueChange event handler and the onValueEdit event handler.
The onValueChange:
This script will run on the client whenever the value property of this widget changes. The widget can be referenced using parameter widget and the new value of the widget is stored in newValue.
The onValueEdit:
This script will run on the client whenever the value of this widget is edited by the user. The widget can be referenced using parameter widget and the new value of the widget is stored in newValue. Unlike onValueChange(), this runs only when a user changes the value of the widget; it won't run in response to bindings or when the value is set programmatically.
Why is this happening?
Since your logic is set on the onValueChange event handler, this will be triggered everytime the dateBox widget value is changed, even programmatically; Hence, form.otDateBox.value = null; is triggering the logic over and over again. The reason why it is being triggered over and over again is due to your comparison logic:
if(otdate <= pastdate)
Here, the value of otdate has become null wich when converted to number Number(null) the value is 0(zero). The value of pastdate is obviously a number greater than zero, eg 1555413900712. So obviously, zero is less than or equal to 1555413900712 and that is why you are triggering an infinite loop.
So, in summary, there is only one way to fix this. Set the logic inside the onValueEdit event handler instead of the onValueChange.

How to update content in Row after selection in dojo datagrid

I have created one dojo datagrid. Every column has a formatter attached to it. When grid is generated the formatter is called. Now I want it so that if a user selects any row the formatter will be called and some strings should be attached to the selected row's column element.
Like grid is like this :
COLUMN
-------
a
b
c
and now user selects the 2nd row, the grid should change to :
COLUMN
-------
a
b SELECTED
c
Currently I implemented it like this :
if(this.grid.selection.selectedIndex !== -1){
retrun value + "SELECTED";
}else{
return value;
}
Can you please suggest a some good way of doing this? Please note that "SELECTED" string should not be added to the grid store.
The formatted is not hooked into clicking / selection of rows. It is solely performed when the contents (value) of a cell is set. Instead you'd want to move focus over to onRowClicked - an event on the grid component. It works like this:
grid.onRowClick = onRowClickHandler;
I wouldnt know which of following samples would put you closest to your goal but onRowClickHandler could be setup as such:
function onRowClickHandler(evt) {
var rows = this.selection.getSelected();
// perform cell rendering here
dojo.forEach(rows, function(row) {
// this row is an item though.. you will have row._O as its index
});
}
OR
function onRowClickHandler(e) {
var cellClicked = this.focus.cell
cellClicked.formatter();
}
However you may find that there are not much references to the viewable data anywhere in the grid component.. You could use following query selectors to find cell data and update the viewed html by calling formatter on each value. You would need to capture a previous selection for 'teardown' of your custom setting of values though.
var prevSelectedRows = [];
function onRowClickHandler(evt) {
var idx = this.selection.selectedIndex,
rawRow = dojo.query(".dojoxGridRow:nth-child("+(idx+1)+")", this.domNode)[0],
self = this;
// perform resetting of viewable values
dojo.forEach(prevSelectedRows, function(raw) {
dojo.query('.dojoxGridCell', raw).forEach(function(cellDOM, i) {
cellDOM.innerHTML = cellDOM.innerHTML.replace("SELECTED", "");
});
});
prevSelectedRows = []; // reset prev selection
// look into grid.view.content for methods on this
// perform setting of viewable values (SELECTED)
dojo.query('.dojoxGridCell', rawRow).forEach(function(cellDOM, i) {
// this function might be of interest, lets see how it looks in console
console.log(self.layout.cells[i].formatter);
cellDOM.innerHTML = cellDOM.innerHTML + "SELECTED"
});
prevSelectedRows.push(rawRow);
}

Is there some way to force 'updatedisplaylist' immediately rather than at later some point

In flex component life cycle, after we make some change in a components property, invalidation methods schedules a call to methods like commitProperties, updateDisplayList, etc for some later time. I need to call the updateDisplayList instantaneously. Is there some direct way to do this.
Currently, both the labels are changed simultaneously after completion of the loop. Instead I need it to work like this, to first render the updated 'myButton1' label then enter the loop and then update myButton2's label. I know, it is elastic race track issue, but isn't there some way to achieve this ?
myButton1.label = 'New Label1' ;
// Some logic to forcibly make the screen reflect it
for (var i:int = 0; i < 500 ; i ++){
//a dummy loop
}
myButton2.label = 'New Label2' ;
You can use myButton1.validateNow() but it's use is discouraged, for you may end up having the same component update itself multiple times on the same frame.
Use validateNow() . But, I would use it sparingly. using invalidateDisplayList() will force updateDisplayList() to run on the next renderer event.
A render event happens on each frame. 24 frames happen each second by default for Flex. Are you sure need to change these values quicker?
I would set the label for myButton1, then put the remaining code into a separate method and call that method using callLater:
private function foo():void {
myButton1.label = 'New Label1';
this.callLater(bar);
}
private function bar():void {
for (var i:int = 0; i < 500 ; i ++){ //a dummy loop
}
myButton2.label = 'New Label2';
}
This way myButton1 will update to show the new label before going into your loop since callLater doesn't call bar until after the event queue is cleared, giving myButton1 a chance to update.
invalidateDisplayList() or valdiateNow() will do it for you however excess of using these will end up memory leaks.

Resources