Note that there are some explanatory texts on larger screens.

plurals
  1. POCan I get some advice on JavaScript delegates?
    primarykey
    data
    text
    <p>I'm rusty with delegates and closures in JavaScript, and think I came across a situation where I'd like to try to use one or both.</p> <p>I have a web app that behaves a lot like a forms app, with fields hitting a server to change data on every onBlur or onChange (depending on the form element). I use ASP.NET 3.5's Web Services and jQuery to do most of the work.</p> <p>What you need to know for the example:</p> <ul> <li><code>isBlocking()</code> is a simple mechanism to form some functions to be synchronous (like a mutex)</li> <li><code>isDirty(el)</code> checks to make sure the value of the element actually changed before wasting a call to the server</li> <li><code>Agent()</code> returns a singleton instance of the WebService proxy class</li> <li><code>getApplicationState()</code> passes a base-64 encoded string to the web service. This string represents the state of the application -- the value of the element and the state are passed to a service that does some calculations. The onSuccess function of the web service call returns the new state, which the client processes and updates the entire screen.</li> <li><code>waitForCallback()</code> sets a flag that <code>isBlocking()</code> checks for the mutex</li> </ul> <p>Here's an example of one of about 50 very similar functions:</p> <pre><code>function Field1_Changed(el) { if (isBlocking()) return false; if (isDirty(el)) { Agent().Field1_Changed($j(el).val(), getApplicationState()); waitForCallback(); } } </code></pre> <p>The big problem is that the <code>Agent().Field_X_Changed</code> methods can accept a different number of parameters, but it's usually just the value and the state. So, writing these functions gets repetitive. I have done this so far to try out using delegates:</p> <pre><code>function Field_Changed(el, updateFunction, checkForDirty) { if (isBlocking()) return false; var isDirty = true; // assume true if (checkForDirty === true) { isDirty = IsDirty(el); } if (isDirty) { updateFunction(el); waitForCallback(); } } function Field1_Changed(el) { Field_Changed(el, function(el) { Agent().Field1_Changed($j(el).val(), getTransactionState()); }, true); } </code></pre> <p>This is ok, but sometimes I could have many parameters:</p> <pre><code> ... Agent().Field2_Changed($j(el).val(), index, count, getApplicationState()); .... </code></pre> <p>What I'd ultimately like to do is make one-linen calls, something like this (notice no <code>getTransactionState()</code> calls -- I would like that automated somehow):</p> <pre><code>// Typical case: 1 value parameter function Field1_Changed(el) { Field_Changed(el, delegate(Agent().Field1_Changed, $j(el).val()), true); } // Rare case: multiple value parameters function Field2_Changed(el, index, count) { Field_Changed(el, delegate(Agent().Field1_Changed, $j(el).val(), index, count), true); } function Field_Changed(el, theDelegate, checkIsDirty) { ??? } function delegate(method) { /* create the change delegate */ ??? } </code></pre> <p>Ok, my first question is: Is this all worth it? Is this harder to read but easier to maintain or the other way around? This is a pretty good undertaking, so I may end up putting a bounty on this one, but I'd appreciate any help you could offer. Thanks!</p> <p><strong>UPDATE</strong></p> <p>So, I've accepted an answer based on the fact that it pointed me in the right direction. I thought I'd come back and post my solution so that others who may just be starting out with delegates have something to model from. I'm also posting it to see if anybody wants to try an optimize it or make suggestions. Here's the common <code>Field_Changed()</code> method I came up with, with <code>checkForDirty</code> and <code>omitState</code> being optional parameters:</p> <pre><code>function Field_Changed(el, args, delegate, checkForDirty, omitState) { if (isBlocking()) return false; if (!$j.isArray(args) || args.length == 0) { alert('The "args" parameter in Field_Changed() must be an array.'); return false; } checkForDirty = checkForDirty || true; // assume true if not passed var isDirty = true; // assume true for updates that don't require this check if (checkForDirty === true) { isDirty = fieldIsDirty(el); } if (isDirty) { omitState = omitState || false; // assume false if not passed if (!omitState) { var state = getTransactionState(); args.push(state); } delegate.apply(this, args); waitForCallback(); } } </code></pre> <p>It handles everything I need it to (check for dirty, applying the application state when I need it to, and forcing synchronous webservice calls. I use it like this:</p> <pre><code>function TransactionAmount_Changed(el) { Field_Changed(el, [cleanDigits($j(el).val())], Agent().TransactionAmount_Changed, true); } </code></pre> <p><code>cleanDigits</code> strips out junk characters the user may have tried to type in. So, thanks to everyone, and happy coding!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload