Is ajax breaking my javascript objects? - asp.net

I have a page that does ASP.NET ajax postbacks using UpdatePanels. In some javascript, I set up some objects in the window.onload event, which works great. When I do a postback though, it seems like my objects are messed up.
One object which was receiving events from a table, is no longer receiving the events. I also had a case where objects which has local references to buttons wouldn't be able to update them. Here's the button javascript that was getting messed up:
function EditItemPage(clientId)
{
this.saveButton = $get(clientId + ""_{2}"")
this.publishButton = $get(clientId + ""_{3}"")
this.exitButton = $get(clientId + ""_{4}"")
EditItemPage.prototype.GoDirty = function()
{
//it works if i add these, but i'd rather not have to.
this.saveButton = $get(clientId + ""_{2}"")
this.publishButton = $get(clientId + ""_{3}"")
this.exitButton = $get(clientId + ""_{4}"")
this.saveButton.disabled = false;
this.publishButton.value = 'Save and Publish';
this.exitButton.value = 'Discard changes and Exit';
}
}
So after I do a postback, the button references are messed up unless i reset them as I did in the GoDirty() function.
Any insight?

The this keyword (special variable) changes based on what function is calling it. Basically, it's an issue of scope. You need to either do a closure around the function which is being called on the ajax response, OR put what you need into the global scope, OR do what you are doing (which you don't like).
Writing the closure is the "right" way.
You may be familiar with the way the this variable changes scope based on events for form inputs. For a textbox, if you use the onblur event, the this refers to the textarea which just lost focus.
See this question for an example of how to do the closure.
This is also another good resource.
(I'm sure I could copy and paste the examples in here for you, but that seems redundant)

Related

Asp.net webforms autosave

I understand this may be an elementary question, but I'm new to Asp.net webforms, so please bear with me.
I have a lengthy form on a page that I would like to autosave when users type in a field, or make a selection. The problem is, all I've been able to find online is autosaves that work on a timer. I'd prefer that it saves as the user makes their edits. Also I would like just the individual form element being edited to be sent to the server to avoid sending the entire page back each time.
I've read that I should use a webservice to accomplish this, but since I want to autosave individual items and not the whole form on a timer, how would I set up a webservice to accomplish this? I'm new to webservices I'd like to know what to read up on. Any links are appreciated.
Also, how is the autosave functionality effected when using asp.net validation controls? I've looked around but can't tell if the entire page needs to be valid to make a trip to the server, or if just a single valid item can be sent itself.
Thanks for any help!
If you set AutoPostBack=True on the field, and you add an OnChange event for it (this will vary depending on the type of field the user is interacting with), you can execute a save. Don't call Page.Validate in the methods where you're doing these updates. Call it when you hit the Submit button.
This could cause a LOT of round trips to the server, and it's a lot of code to write and debug.
The Timer approach is one call to one method on a repetitive basis. If you can I'd recommend going with a timer, but sometimes that's not an option.
Generally speaking this is what you'll want to setup on the client-side. Ideally, you will end up with lots of tiny requests which do not require much power on the back-end. This however depends on lots of variables including the database engine you're using.
$(document).ready(function () {
$("input").blur(OnFieldChanged);
});
function OnFieldChanged()
{
var $this = $(this);
var isValid = ValidateField($this);
if (isValid)
{
SaveField($this);
}
}
function SaveField($field)
{
if ($this.val() === $this.prop("oldVal")) return;
var data = {
id: $("idfield").val()
};
data[$field.attr("id")] = $field.val();
$.post({..}).done(function() {
NotifySaved($this);
$this.prop("oldVal", $this.val());
});
}
function ValidateField($field)
{
// Validate the field with your method of choice, manually call Microsoft's client-side validate function or switch to jquery validate.
return true;
}

Detect template change in Meteor

I'm looking to make an element flash on screen when the underlying collection is updated.
It seems to me that it would make to have an equivalent of Template.my_template.rendered = function(){} which is fired every time the template is updated.
Ideally, this function would not fire the first time the template is rendered.
This is seems like such an obvious use case, am I missing something?
For Meteor < 0.8
You should use Template.myTemplate.created to do something for the very first time. From the docs Template.myTemplate.rendered is fired everytime there is a change including the first time. If you want to limit it to only the second time and changes after that (I'm guessing this is what you want), you have to write some custom logic. Currently there is no Meteor api that supports that.
For Meteor-0.8
It seems like this API underwent some backwards incompatible changes in Meteor-0.8.
There is an elegant way to achieve this as described Adaptation to the new Meteor rendered callback here. Bascially you should modify whatever function you are attaching to the variables inside your Template's javascript by calling a helper function once. For example,
var renderCount = 1;
var myHelper = function () {
console.log("rendered #" + renderCount);
renderCount++;
};
Template.myTemplate.myVariable = function () {
myHelper();
return this.name;
};
Hope this helps. There is also another alternative approach in that same repo. You might like that one.
There is no simple solution; more discussion here: https://groups.google.com/forum/#!topic/meteor-talk/iQ37mTP3hLg

Asp Firing All Validation Summaries

I need to make multiple validation summaries validate their controls and display any error messages.
I have a large form that I've broken into separate panels, each with it's own validation group and summary. I have one button that must validate the entire page and cause all the validation groups to be validated and show the error message.
My idea is to just iterate through a collection of Validators/Validation Summaries/Validation Groups in the code behind and fire their validate events, but I'm having trouble implementing it so that the validations summaries/errors appear on the page. Any ideas?
EDIT: I made a JavaScript function to try and get it working on the client side
<script type="text/javascript">
function validate() {
var t1 = Page_ClientValidate("vgpEmpInfo");
var t2 = Page_ClientValidate("vgpPanelA");
if (!t1 || !t2) return false;
return true;
}
</script>
But this only validates and displays the last validation group called, in this case Panel A.
So you are looking to do it all on the client then, not the server? The server would be easier as you could call Page.Validate("group"), and that would work for all the validation summaries.
Page_ClientValidate I didn't realize that would hide all the groups... but what you could try to do is call Page_ClientValidate for all. Now I'm not sure, but I think that it might just hide the <ul> representing the list, but I'm not 100% sure, so you may be able to just show all the <ul>'s representing each summary.... otherwise, you'd have to look at validatorValidate client method. Never done this, but seems like this might work, though the latter is going to be a real pain because you have to examine custom attributes on the validator span, and process accordingly.
HTH.

Why does $find(strSomeOtherRadAjaxPanel) return null?

Problem context:
1) rcbComboBoxInRadPanel is a Telerik RadComboBox.
2) rcbComboBoxInRadPanel has "OnClientSelectedIndexChange" event which fires "itemSelected."
3) rcbComboBoxInRadPanel is contained a radAjaxPanel called "foo."
4) strSomeOtherRadAjaxPanel names a RadAjaxPanel that exists outside of "foo."
5) $find(strSomeOtherRadAjaxPanel) returns a valid RadAjaxPanel if executed alone.
function itemSelected(rcbComboBoxInRadPanel)
{
var strComboBoxInRadPanel = rcbComboBoxInRadPanel.get_id();
var intRecordID = rcbComboBoxInRadPanel.get_value();
$find(strSomeOtherRadAjaxPanel).ajaxRequest(intRecordID);
}
It appears that $find(strSomeOtherRadAjaxPanel) always returns null when called from the "OnClientSelectedIndexChange" event of rcbComboBoxInRadPanel.
Is there another way for me obtain a valid reference to the RadAjaxPanel using $find(strSomeOtherRadAjaxPanel)?
Any help you can offer would be helpful.
Can you obtain reference to the strSomeOtherAjaxPanel from other client handler of the combo or when it is moved outside of its ajax panel holder? If the strSomeOtherAjaxPanel is initialized properly on the client, it should be available in each of these cases.
check your rendered html source code. ASP dynamically generates clientID names so your server side IDs may not have persisted. They probably now look something like ctl100aFMLksdjflFML
Either target them some other way (like class name, jQuery search, etc) or set the client ID mode to static (if it is the only instance of this object) then try again.

Flash: How to dispatch a click event at the top of a loaded .swf?

So I'm trying to build a tool that will allow me and other users to all open the same .swf, and then I as the Admin user am able to interact with mine while they all see my mouse movements and button clicks etc on theirs.
I'm using BlazeDS to manage this and I'm getting data sent back and forth etc - no difficulties there. The issue I'm running into is this:
In an "Admin" instance, I click a button. I capture that X and Y, then tell Blaze to tell my clients to dispatch a Click event at that X and Y. On my client side, I get that data and dispatch a Click event at that X and Y - but the click is actually caught at the stage level. The click on my client side takes place UNDER all of my buttons and other content - so the whole thing fails.
Does this make sense? Is there a way to tell it to start the click event at the top?
If you are unable to architect the loaded swf's to use a better architecture you could try something a little more hackish to get buttons working.
Have a look at the methods getObjectsUnderPoint and areInaccessibleObjectsUnderPoint of the DisplayObjectContainer. Combined with hasEventListener you should be able to emulate what you want.
Here is some untested pseudo-code:
function detectClick(pt:Point):void
{
var objsUnderPoint:Array = containerStage.getObjectsUnderPoint(pt);
var clickable:Array = [];
for each(dispObj:DisplayObject in objsUnderPoint)
{
if(dispObj.hasEventListener(MouseEvent.CLICK))
{
clickable.push(dispObj);
}
}
if(clickable.length)
{
// sort on depth here
// that might be tricky since you'll be looking at grandchildren
// and not just children but it is doable.
var topMostClickable:DisplayObject = ???
topMostClickable.dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, false));
}
}
areInaccessibleObjectsUnderPoint is important if you think their might be security restrictions (e.g. cross-domain issues) so you can debug if things go wrong.
Also note that you may want to (or need to) fill in more details of the MouseEvent (like the proper target, localX, localyY etc.)
Sounds like you need to set focus to the top most component of the x and y positions before dispatching the click event.
That said, I wonder what the use case is for something like this; as opposed to using a screen sharing tool such as Connect.
This seems like a poor way to implement what you are trying to do. If you "click" in the admin tool you are probably actually triggering some event. Why not trigger that event instead of sending the mouse click?
I'd just keep a map of actions and then when something happens in the Admin interface send the key to the action.
e.g.
In the admin:
myButton.addEventListener(MouseEvent.CLICK, handleClickButton);
function handleClickButton(event:MouseEvent):void
{
doSomeAction();
sendTriggerToClient(MyActions.SOME_TRIGGER);
}
In the client:
var actionMap:Object = {};
actionMap[MyActions.SOME_TRIGGER] = doSomeAction;
function receiveTriggerFromAdmin(trigger:String):void
{
var responseFunc:Function = actionMap[trigger];
responseFunc();
}
I hope that pseudo-code makes sense. Just abstract what happens as a result of a click into a separate function (doSomeAction) and then have the admin send a message before calling that function. In the client wait for any trigger that comes through and map it to the same function.

Resources