Is there a way to limit viewDisplay event to be triggered only when the view (day, week, month) is changed and not when next/previous/today is clicked?
Ahh yes- I thought i was the only one that thought this was a bit misleading and lodged a bug....
Here you go.
You need to define a global variable before the calendar loads! Leave it undefined- or change it how you like. This also solves another bug- it prevents the viewChange event from firing TWICE when the calendar loads :)
var listView
Then in the calendar init
viewDisplay: function(view) {
if (lastView == undefined) { lastView = 'firstRun'; }
if (view.name != lastView )
{
if (view.name == 'month')
{
//What todo for month?
}
if (view.name == 'basicDay')
{
//What todo for BasicDay
}
lastView = view.name;
}
This is what I use currently to overcome this problem. But you have to hard codeall views into the code.. which is not good really.
Related
I am using FullCalendar in my project. I used background events, rendering="background". How can I detect if user click on the background events? I try this but it doesnot work since all dates cannot be clicked.
dayClick: function (start, end, allDay, jsEvent, view,color,calEvent) {
if (calevent.rendering==="background") {
alert('Click Background Event Area');
}
else{
$('#modal1').modal('show');
}
if (start.isBefore(moment())) {
$('#calendar').fullCalendar('unselect');
return false;
}
},
Since fullCalendar doesn't expose an "click" type event on background events, the only way I can think of to do this is essentially a DIY approach. The basic idea:
Handle the "select" event
Fetch all the events currently in fullCalenar's memory, using the "clientEvents" method.
Loop through them all and check whether any of them are background events, and if so, whether they overlap with the selected time period. If they do, then that's the event that was clicked on.
I haven't tested this, but it's based on some old code I found, so hopefully you get the idea:
select: function(start, end, jsEvent, view) {
var cal = $("#calendar"); //put the ID of your calendar element here
var evts = cal.fullCalendar('clientEvents'); //get all in-memory events
var selectedEvent = null;
for (i in evts) {
if (evts[i].rendering == "background" && start.isBefore(evts[i].end) && end.isAfter(evts[i].start)) {
selectedEvent = evts[i];
}
}
}
The only flaw in this is that "select" allows selection of a time period, not just a single click, so it could be that the selection is overlapping the background event, and not wholly contained within it. You might be able to adjust the logic a little bit if that doesn't suit you - e.g. to require that both start and end are within the event's boundaries.
I'm trying to use a flexlib schedule viewer in my application.
I want to have it so that when I click on a scheduled event, it calls a function in my main app (that will allow me to edit the event). But there doesn't seem to be any specific function for anything like this built into the class ie no event dispatched when I click on an event.
I can use the 'click' function to detect that the item has been clicked on.. and have tried something like this:
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
<code:ScheduleViewer id="exerciseSeries" click="exerciseClickHandler(event)" />
This method isn't very reliable because if it only works the first time.. once an item is selected, it stays selected so all following clicks on the item fulfills the condition.
Is there any way to determine whether an event was being clicked on?
Or do I have to extend the component and add some sort of clickEvent when an event is clicked on.
Since exerciseClickHandler is firing up when you click on the component, wouldn't this work?
Instead of
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
write
private function exerciseClickHandler(event:MouseEvent):void{
switch (exerciseSeries.selectedItem)
{
//code
case xy:
break;
}
}
or
private function exerciseClickHandler(event:MouseEvent):void{
//do something with exerciseSeries.selectedItem
}
What I mean is that you wrote that everything stops after the first element is clicked. And according to the code you provided it has to stop, beacuse after the first click exerciseSeries.selectedItem won't be null anymore, since it's selected. So remove the conditional you wrote and use the instance.
I'd suggest you set up a ChangeWatcher to keep an eye on the selectedItem (or selectedItems if you are going to allow multiple selection at some point). Example:
protected exerciseSeriesCreationCompleteHandler(event:FlexEvent):void{
ChangeWatcher.watch(this,['exerciseSeries','selectedItem'], handleChange_SelectedItem);
}
protected function handleChange_SelectedItem(event:PropertyChangeEvent):void{
// Either
dispatchedEvent(//some custom event);
// Or
someDirectMethodCall();
}
An alternative would be to search for an instance of the the event class in the view hierarchy under the mouse coordinates whenever a user clicks.
//Attach this click handler to the component
private function handleClick(event : MouseEvent) : void {
var obj : *EventClass*= null;
var applicationStage : Stage = FlexGlobals.topLevelApplication.stage as Stage;
var mousePoint : Point = new Point(applicationStage.mouseX, applicationStage.mouseY);
var objects : Array = applicationStage.getObjectsUnderPoint(mousePoint);
for (var i : int = objects.length - 1; i >= 0; i--) {
if (objects[i] is *EventClass*) {
obj = objects[i] as *EventClass*;
break;
}
}
if(obj is *EventClass*){
//Dispatch some custom event with obj being the item that was clicked on.
}
}
Where EventClass is the class of the objects that represent events
I have had similar problems and sometimes you can get by with wrapping the object with a Box and putting the click event on the Box. If you have not already tried that, it's a cheap, easy fix (if it works for you).
<mx:Box click="exerciseClickHandler(event)">
<code:ScheduleViewer id="exerciseSeries" />
</mx:Box>
I've got a particularly large form in an page. When the form is validated and a field is invalid, I want to scroll the window to that control. Calling the control's Focus() doesn't seem to do this. I've found a JavaScript workaround to scroll the window to the control, but is there anything built into ASP.NET?
Page.MaintainScrollPositionOnPostBack = False
Page.SetFocus(txtManagerName)
Are you using a Validation Summary on your page?
If so, ASP.NET renders some javascript to automatically scroll to the top of the page which may well override the automatic behaviour of the client side validation to focus the last invalid control.
Also, have you turned client side validation off?
If you take a look at the javascript generated by the client side validation you should see methods like this:
function ValidatorValidate(val, validationGroup, event) {
val.isvalid = true;
if ((typeof(val.enabled) == "undefined" || val.enabled != false) &&
IsValidationGroupMatch(val, validationGroup)) {
if (typeof(val.evaluationfunction) == "function") {
val.isvalid = val.evaluationfunction(val);
if (!val.isvalid && Page_InvalidControlToBeFocused == null &&
typeof(val.focusOnError) == "string" && val.focusOnError == "t") {
ValidatorSetFocus(val, event);
}
}
}
ValidatorUpdateDisplay(val);
}
Note the call to ValidatorSetFocus, which is a rather long method that attempts to set the focus to the control in question, or if you have multiple errors, to the last control that was validated, using (eventually) the following lines:
if (typeof(ctrl.focus) != "undefined" && ctrl.focus != null) {
ctrl.focus();
Page_InvalidControlToBeFocused = ctrl;
}
To get this behaviour to work, you would ideally need to ensure that all your validators are set to be client-side - server side validators will obviously require a postback, and that might affect things (i.e. lose focus/position) - and setting MaintainScrollPositionOnPostBack to true would probably cause the page to reload to the submit button, rather than the invalid form element.
Using the server side .Focus method will cause ASP.NET to render out some javascript "on the page load" (i.e. near the bottom of the page) but this could be being overriden by one of the other mechanisms dicussed above.
SO I believe the problem is because I was trying to focus on HtmlGenericControls instead of WebControls.
I just ended up doing a workaround based off of:
http://ryanfarley.com/blog/archive/2004/12/21/1325.aspx
http://www.codeproject.com/KB/aspnet/ViewControl.aspx
...in the interest of time.
public static void ScrollTo(this HtmlGenericControl control)
{
control.Page.RegisterClientScriptBlock("ScrollTo", string.Format(#"
<script type='text/javascript'>
$(document).ready(function() {{
var element = document.getElementById('{0}');
element.scrollIntoView();
element.focus();
}});
</script>
", control.ClientID));
}
Usage:
if (!this.PropertyForm.Validate())
{
this.PropertyForm.ErrorMessage.ScrollTo();
failed = true;
}
(Although it appears Page.RegisterClientScriptBlock() is deprecated for Page.ClientScript.RegisterClientScriptBlock()).
Adding MaintainScrollPositionOnPostback is the closest that ASP.NET has built in, but won't necessarily jump to the invalid field(s).
<%# Page MaintainScrollPositionOnPostback="true" %>
Very simple solution is to set the SetFocusOnError property of the RequiredFieldValidator (or whichever validator control you are using) to true
Are you sure Focus() won't do what you're describing? Under the hood, it is essentially doing the "JavaScript workaround" - it writes some JS to the page which calls focus() on the control with the matching ID:
Whichever control had Focus() called last before the page finishes processing writes this to the page:
<script type="text/javascript">
//<![CDATA[
WebForm_AutoFocus('txtFocus2');//]]>
</script>
Please insert these into your OnClick event
Page.MaintainScrollPositionOnPostBack = false;
Page.SetFocus("cliendID");
// or
Page.setFocus(control);
You should looks into jQuery and the ScrollTo plugin
http://demos.flesler.com/jquery/scrollTo/
I've achieved something similar using basic HTML fragments. You just leave an element with a known ID:
<span id="CONTROL-ID"></span>
And then either via script, on on the server side change the url:
window.location += "#CONTROL-ID";
In the first case the page won't reload, it will just scroll down to the control.
Paste the following Javascript:
function ScrollToFirstError() {
Page_ClientValidate();
if (Page_IsValid == false) {
var topMostValidator;
var lastOffsetTop;
for (var i = 0; i < Page_Validators.length; i++) {
var vld = Page_Validators[i];
if (vld.isvalid == false) {
if (PageOffset(vld) < lastOffsetTop || lastOffsetTop == undefined) {
topMostValidator = vld;
lastOffsetTop = vld.offsetTop;
}
}
}
topMostValidator.scrollIntoView();
}
return Page_IsValid;
}
function PageOffset(theElement) {
var selectedPosY = 0;
while (theElement != null) {
selectedPosY += theElement.offsetTop;
theElement = theElement.offsetParent;
}
return selectedPosY;
}
Then call ScrollToFirstError() in your OnClientClick of the button that is saving, make sure the button has CausesValidation=true as well.
There you have it.
On my submit button, what I'd like to do is OnClick show a "Please wait" panel and hide the button, UNLESS the validators say something's invalid - then I need the buttons still showing obviously. Otherwise I have a validation summary showing erros and no way to submit again.
Most articles I find about doing this want to use Page_ClientValidate() function to tell the page to validate itself, but this comes back undefined for me, as does Page_IsValid variable. Here is the function I'm trying to use - what am I missing?:
function PleaseWaitShow() {
try {
alert("PleaseWaitShow()");
var isPageValid = true;
// Do nothing if client validation is not active
if (typeof(Page_Validators) == "undefined") {
if (typeof(Page_ClientValidate) == 'function') {
isPageValid = Page_ClientValidate();
alert("Page_ClientValidate returned: " + isPageValid);
alert("Page_IsValid=" + Page_IsValid);
} else {
alert("Page_ClientValidate function undefined");
}
} else {
alert("Page_Validators undefined");
}
if(isPageValid) {
// Hide submit buttons
document.getElementById('pnlSubmitButton').style.visibility = 'hidden';
document.getElementById('pnlSubmitButton').style.display = 'none';
// Show please wait panel
document.getElementById('pnlPleaseWait').style.visibility = 'visible';
document.getElementById('pnlPleaseWait').style.display = 'block';
} else {
alert("page not valid - don't show please wait");
}
} catch(er) {
alert("ERROR in PleaseWaitShow(): " + er);
}
}
change this line "if (typeof(Page_Validators) == "undefined") " to
if (typeof(Page_Validators) != "undefined")
According to the section "The Client-Side API" on the page "ASP.NET Validation in depth":
Page_IsValid | Boolean variable | Indicates whether the page is currently valid. The validation scripts keep this up to date at all times.
Indeed, watching this variable in FireBug on a form with ASP.NET client side validation enabled, it does get updated as I fill in details of the form (incorrectly, or correctly).
Obviously, if you've disabled client script on your validators or the validation summary, then this variable won't be available to you.
Just check
if(Page_IsValid)
{
//Yourcode
}
This works if you have validators in the page, which excludes the validation summary.
Page_ClientValidate() is not any standard javascript function i know of
I believe I've found a "kind of" answer.
I still cannot identify why my page will not identify "Page_ClientValidate()" or "Page_IsValid" - this part is still unanswered.
However, I am using a number of PeterBlum validators on the page, and those do provide a "VAM_ValOnSubmit()" that returns true/false. So this may be the solution. I might just have to be sure all the validators are PeterBlum to catch them all.
Not the greatest solution, but better than I've gotten so far. I'm still open to answers on the "Page_IsValid" portion.
There's an ASP.Net forum thread on this topic: Button that prevents multiple clicks
Here's the solution (in code behind):
private void BuildClickOnceButton(WebControl ctl)
{
System.Text.StringBuilder sbValid = new System.Text.StringBuilder();
sbValid.Append("if (typeof(Page_ClientValidate) == 'function') { ");
sbValid.Append("if (Page_ClientValidate() == false) { return false; }} ");
sbValid.Append(ctl.ClientID + ".value = 'Please wait...';");
sbValid.Append(ctl.ClientID + ".disabled = true;");
//GetPostBackEventReference obtains a reference to a client-side script function that causes the server to post back to the page.
sbValid.Append(ClientScript.GetPostBackEventReference(ctl, ""));
sbValid.Append(";");
ctl.Attributes.Add("onclick", sbValid.ToString());
}
Goal:
Allow the user to delete a record by dragging a row from an AdvancedDataGrid, dropping it onto a trash-can icon and verify the user meant to do that via a popup alert with "OK" and "Cancel" buttons.
What is working:
Dragging/Dropping a row onto the trash icon.
If the user clicks the "OK" button, the record is deleted.
If the user clicks the "Cancel" button, the operation is canceled.
Problem:
After the user clicks the "Cancel" button and the popup alert closes, no rows in the ADG can be dragged. I've discovered that after sorting the ADG, by clicking on a column header, the user can begin dragging rows again.
Code: (changed from original post)
<mx:Image source="{trashImage}" buttonMode="true"
toolTip="drag a participant here to delete them from the project"
dragDrop="deleteParticipantDrop(event)" dragEnter="deleteParticipantEnter(event)"
dragExit="deleteParticipantDragExit(event)" top="4" right="122" id="image2" />
// trashImage Event Handlers:
private function deleteParticipantEnter(event:DragEvent):void
{
var component:IUIComponent = IUIComponent(event.currentTarget);
dragComponent = component;
DragManager.acceptDragDrop(component);
DragManager.showFeedback(DragManager.MOVE);
deleteParticipantDragEvent = event;
}
private function deleteParticipantDrop(event:DragEvent):void
{
var selectedKitNum:String = memberRpt.selectedItem.KitNum;
var selectedName:String = memberRpt.selectedItem.ParticipantName;
var component:IUIComponent = IUIComponent(event.currentTarget);
dragComponent = component;
DragManager.acceptDragDrop(component);
isEditingParticipantInfo = false;
isDeletingParticipant = true;
deleteParticipantDropEvent = event;
event.stopImmediatePropagation(); // Added as per mrm
alert.confirm("Are you sure you want to delete this participant, Kit #" + memberRpt.selectedItem.KitNum + " (" +
memberRpt.selectedItem.ParticipantName + ") from the project? This cannot be reversed!! An email will be " +
"sent to notify this participant and you will receive a copy of it for your records.", confirmRemoveParticipant);
}
private function deleteParticipantDragExit(event:DragEvent):void
{
var component:IUIComponent = IUIComponent(event.currentTarget);
dragComponent = component;
DragManager.acceptDragDrop(component);
DragManager.showFeedback(DragManager.NONE);
}
private function confirmRemoveParticipant(event:CloseEvent):void
{
if (event.detail == Alert.YES)
{
deleteReason = DeleteParticipantTitleWindow(PopUpManager.createPopUp( this, DeleteParticipantTitleWindow , true));
dispatchEvent(deleteParticipantDropEvent); // Added as per mrm
PopUpManager.centerPopUp(deleteReason);
deleteReason.showCloseButton = true;
deleteReason.title = "Reason for removal from project";
deleteReason.addEventListener("close", cleanupRemoveParticipant);
deleteReason["cancelButton"].addEventListener("click", cleanupRemoveParticipant);
deleteReason["okButton"].addEventListener("click", finalizeDeleteParticipant);
isDeletingParticipant = false;
}
else
{
cleanupRemoveParticipant();
}
}
private function cleanupRemoveParticipant(event:Event = null):void
{
memberRpt.invalidateDisplayList();
memberRpt.executeBindings();
if (deleteReason != null)
{
PopUpManager.removePopUp(deleteReason);
deleteReason = null;
}
}
public function finalizeDeleteParticipant(event:Event):void
{
if (deleteReason.reason.text != null)
{
selectedReportItem = memberRpt.selectedItem;
selectedReportItemIndex = memberRpt.selectedIndex;
memberReportData.removeItemAt(selectedReportItemIndex);
}
else
{
alert.info("You must provide a reason for removing a participant from your project!!");
}
cleanupRemoveParticipant();
}
Thanks in advance for all helpful suggestions.
Have you tried running the validateNow() method on the ADG after the cancel event?
Here is some more information on the validateNow() method.
Why you need to know about validateNow...
I really do think this is what you're looking for! Please let us know if that is the case...
Try refreshing the data bindings on the datagrid using executeBindings and/or invalidateDisplayList in the enclosing control.
To be honest this sounds a bit like a bug. Have you posted this on flexcoders? The Adobe guys hang out on there (probably here too, but definitely there)
Hang on... just spotted that between the drop event and the cancel button of the popup there is an asynchronous web service call which appears to be handled by GetParticipantOrderInformation. Is that correct?
If yes, then have you tried offering a simpler dialog for Cancel before you do that? I wonder whether the combination of layers of events is causing a problem.
I didn't have any success with refreshing the data bindings on the datagrid via the executeBindings and invalidateDisplayList methods. I also didn't have any luck by showing the confirmation alert before making the webservice call. In fact, I discovered that making the webservice call was completely unnecessary and removed it. So now the code flows like this:
Drag/drop ADG row onto trash icon.
Display confirmation Alert box.
If user clicked "Cancel" button, redisplay the ADG.
But the same problem persists. I'll update the Code section with the latest code.
Here's an idea:
- Just before you create the alert window, stop the DragEvent
event.stopImmediatePropagation();
store the event so we can resume if the user clicks the Yes button
queuedEvent = event as DragEvent;
show the alert window
if the user clicks the yes button, resume the queued event
dispatchEvent(queuedEvent);
DragManager.showFeedback(DragManager.NONE);