SitePoint Sponsor

User Tag List

Results 1 to 25 of 50

Hybrid View

  1. #1
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    referencing function parameters

    I have this JS function:
    Code JavaScript:
    var maxAmount = 250;
    function textCounter(textField, showCountField) {
        if (textField.value.length > maxAmount) {
            textField.value = textField.value.substring(0, maxAmount);
    } else { 
            showCountField.value = maxAmount - textField.value.length;
    }
    }

    I also have a form in which I need ti use the fuction:
    Code JavaScript:
    <body>
    <form>
    <textarea name="ta" rows="6" style="width:340px;" onKeyDown="textCounter(???????,???????);" onKeyUp="textCounter(???????,???????);"></textarea>
    <br>
    <input readonly id="ta2"type="text" name="countDisplay" size="3" maxlength="3" value="250"> Characters Remaining
    </form>
    </body>

    How do I reference my the parameters of my function from the form?

  2. #2
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    The two values of the function are textField and showCountField

    For the first parameter, the this keyword is going to be the textarea field.
    For the second parameter, you could use this.form.elements.countDisplay to refer to the display field.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  3. #3
    dooby dooby doo silver trophybronze trophy
    spikeZ's Avatar
    Join Date
    Aug 2004
    Location
    Manchester UK
    Posts
    13,807
    Mentioned
    158 Post(s)
    Tagged
    3 Thread(s)
    or.....
    Code JavaScript:
    <form>
    <textarea name="ta" rows="6" style="width:340px;" onKeyDown="textCounter(this,countDisplay);" onKeyUp="textCounter(this,countDisplay);"></textarea>
    <br />
    <input id="ta2" type="text" name="countDisplay" size="3" maxlength="3" value="250" readonly /> Characters Remaining
    </form>

    (but Paul is way better at this voodoo than me!)
    Mike Swiffin - Community Team Advisor
    Only a woman can read between the lines of a one word answer.....

  4. #4
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Code JavaScript:
    onKeyDown="textCounter(this,this.form.elements.countDisplay);" onKeyUp="textCounter(this,this.form.elements.countDisplay);"></textarea>

    was unsuccessful. Did i misunderstand?

  5. #5
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by nichemtktg View Post
    was unsuccessful. Did i misunderstand?
    It works for me. Is there something else that's causing the problem?
    If you link us through to a test page, we can find out.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  6. #6
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

  7. #7
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Now the problem is clear as day. The code you claim to have used in post #4 is different from what you actually used.
    Can you see the problem?
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  8. #8
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    I see the difference. Sorry about that. I've been played with it too much. I made the change and it works.

    I found that this also works:
    Code JavaScript:
    onKeyDown="textCounter(this,document.getElementById('ta2'));" onKeyUp="textCounter(this,document.getElementById('ta2'));"

    It makes sense to me though I had to give <input> an id.

    I'm real fuzzy in the use of "this" and I'm unsure how you came-up with "this.form.elements".

    1. I've already spoken to my fuzziness with "this"

    2. I believe the "form" comes from the HTML DOM Form Object. If so, that makes sense, but please confirm.

    3. I'm unclear where the "elements" came form the HTML DOM Form Object talks about "elements[]" if they're the same why drop the "[]"?

    My uncertainty about how to use "this" really bugs me because it seems important based on what I've read, but I haven't found clear general ref for how to use it. any suggestions (other than asking too many questions)?

  9. #9
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by nichemtktg View Post
    I'm real fuzzy in the use of "this" and I I'm unsure how you came-up with "this.form.elements.

    1. I've already spoken to my fuzziness with "this"
    The this keyword is a reference to the context within which the function was executed.

    Quote Originally Posted by nichemtktg View Post
    2. I believe the "form" comes from the HTML DOM Form Object. If so, that makes sense, but please confirm.
    All form fields contain a property called form, that refers to the form element that the field is contain within.

    Quote Originally Posted by nichemtktg View Post
    3. I'm unclear where the "elements" came form the HTML DOM Form Object talks about "elements[]" if they're the same why drop the "[]"?
    Using the array index notation could be used as well, but typically it's not used in preference to object notation.
    this.form.elements['username'] is the same as this.form.elements.username

    But the same goes with any property reference:
    this['form']['elements']['username'] is the same too, though less readable.

    Typically the only reason to use the array notation is when you want to make it clear that actual indexed arrays are used, or when characters occur in the name (a dash for example) that aren't usable as a property notation.

    Quote Originally Posted by nichemtktg View Post
    My uncertainty about how to use "this" really bugs me because it seems important based on what I've read, but I haven't found clear general ref for how to use it. any suggestions (other than asking too many questions)?
    What do you think of the information at the page about the this keyword
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  10. #10
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    regarding who owns the textCounter function, in my script I think its a method of the window object, because it hasn't been copied to a different object, therefore a simple "this" is enough. Please confirm.

  11. #11
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by nichemtktg View Post
    regarding who owns the textCounter function, in my script I think its a method of the window object, because it hasn't been copied to a different object, therefore a simple "this" is enough. Please confirm.
    The textCounter function is not copied to the event handler, so the function will not have an appropriate this keyword reference to the element that triggered the event.

    There are three different techniques that can be used to deal with that problem.

    1. Use traditional event assignment instead, so that the this keyword is available from within the function.
    2. Pass the this keyword separately to the function as an additional function parameter.
    3. Call the function using the this keyword to assign the context from which the function will be called.

    Traditional Event Assignment

    When using this first technique, the HTML code for the form field is much simpler, where a unique identifier is placed on the form to allow scripting to access the form elements:

    Code:
    <form id="countedText">
        <textarea name="ta" rows="6" style="width:340px;"
            onKeyDown="textCounter(this, this.form.elements.countDisplay);"
            onKeyUp="textCounter(this, this.form.elements.countDisplay);">
    </textarea>
    </form>
    so that scripting is used to perform the event assignment instead.
    There are a couple of ways to handle things here.

    One way, the way that I typically prefer, is to store a reference to the display area as a property directly on the textarea field itself:

    Code javascript:
    function countDisplay() {
        var textField = this,
        showCountField = textField.countDisplay;
        ...
    }
    var form = document.getElementById('countedText'),
        textarea = form.elements.ta;
     
    textarea.countDisplay = form.elements.countDisplay;
    textarea.onkeydown = textCounter;
    textarea.onkeyup = textCounter;

    Another way is to pass the count display as a property to the function, but then you cannot use a direct assignment of the function to the event, you have you use an anonymous function so that you can invoke the countDisplay function with the appropriate argument, and pass the this context along to the function as well:

    Code javascript:
    function countDisplay(countDisplay) {
        var textField = this;
        ...
    }
    var form = document.getElementById('countedText'),
        textarea = form.elements.ta,
        countDisplay = form.elements.countDisplay;
    textarea.onkeydown = function () {
        textCounter.call(this, countDisplay);
    };
    textarea.onkeyup = function () {
        textCounter.call(this, countDisplay);
    };

    It can be preferred though to combine those identical functions in to a single event handler function instead:

    Code javascript:
    function countDisplay(countDisplay) {
        var textField = this;
        ...
    }
    function textareaHandler(countDisplay) {
        return function () {
            textCounter.call(this, countDisplay);
        };
    }
    var form = document.getElementById('countedText'),
        textarea = form.elements.ta,
        countDisplay = form.elements.countDisplay;
    textarea.onkeydown = textareaHandler(countDisplay);
    textarea.onkeyup = textareaHandler(countDisplay);

    That gets a bit complicated though, and it why I prefer to use the first example where the field property to store the reference. It's a good technique that only needs to be moved away from if you're concerned about other code over-writing the property.

    Inline Event Attribute

    You are currently using the second technique, which forces you to use an extra parameter in your function to receive a reference to the element. Examples of which are in the previous posts above.

    Pass the Inline Context to the Function

    This third technique is where the call method is used to call the function with an appropriate context, simulating that which scripting automatically does in the first technique:

    Code:
    <textarea name="ta" rows="6" style="width:340px;"
        onKeyDown="textCounter.call(this, this.form.elements.countDisplay);"
        onKeyUp="textCounter.call(this, this.form.elements.countDisplay);"[/color][/s]>
    </textarea>
    where the function still has only the one parameter:

    Code javascript:
    function countDisplay(countDisplay) {
        var textField = this;
        ...
    }

    This technique is disliked though, due to it being another inline event attribute technique, along with .call() to help confuse things.
    Last edited by paul_wilkins; Jul 7, 2011 at 21:43.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  12. #12
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    On second thought, "this" must be referring to the <textarea> because that's where the input is coming from. without the <textarea> input there's nothing for the function to do. Right now for the right reason?

  13. #13
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    And I just realised something.

    You don't even need to set maxChar to a certain value.
    Since you already have the max number as the starting value for the counter, you can retrieve that initial value (no matter what it has since changed to) from the defaultValue property.

    Code:
    counter: form.countDisplay,
    maxChar: 250form.countDisplay.defaultValue,
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  14. #14
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Thanks again for all your help. I followed post #30 through the point where you said, "Here's the full set of code changes that we've gone through here" (right before you made additional improvements). At that point, I ran the script, but couldn't get it to work. What did I miss?

    Your script as I understand it so far:
    HTML Code:
    <!doctype html>
    <html> <head> <title> Counter </title> 
    
    </head> <body>
    <form id="messageArea">
        <textarea name="ta" rows="6" style="width:340px;"> </textarea>
    	<br>
        <input type="text" name="countDisplay" size="3" maxlength="3" value="250"> Characters Remaining
    </form>
    
    <script type="text/javascript">  
    
    var form = document.getElementById('messageArea'),
        calcCharacters = form.elements.ta;
    
    calcCharacters.config = {
        maxChar: 250,
        counter: form.countDisplay
    };
    
    calcCharacters.config = calcCharacters.onkeyup =  function () {
        var config = this.config,
            x = config.maxChar - this.value.length;
        config.counter.value = x;
    }
    </body> </html>

  15. #15
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by nichemtktg View Post
    At that point, I ran the script, but couldn't get it to work. What did I miss?
    You've been following things very well. So well though that you also copied an error in one of the pieces.

    The post went through multiple rewrites throughout the course of the day before it was posted, and one of those rewrites managed to leave some chaff in the works.
    The post has been updated now, but where there was:
    Code:
    form.countDisplay
    that should have instead been
    Code:
    form.elements.countDisplay
    It doesn't change the working of the script, but it's the more formal and properly correct way to access things.
    Another one that is somethiing for which I should be shot for leaving in though is:
    Code:
    calcCharacters.config = calcCharacters.onkeyup =  function () {
    which needs to have the first part excised.
    Code:
    calcCharacters.config = calcCharacters.onkeyup = function () {
    A last thing that I noticed in your script, which is what's actually causing the largest problem, is that it needs to end with a </script> closing tag. Otherwise it just won't work at all.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  16. #16
    SitePoint Evangelist
    Join Date
    Jun 2010
    Posts
    455
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Thank-you. It works great.

    Now back to #30, you said. "This can then be further improved on, so that the config is not attached to the textarea, but instead is attached to the event function using a closure technique", but I don't see exactly how to apply the change you suggested. Can you say again the change you you were referring to?

    PS: Should've caught that missing <\script> - Please excuse me.

    Current script:
    HTML Code:
    <!doctype html>
    <html> <head> <title> Counter </title> 
    
    </head> <body>
    <form id="messageArea">
        <textarea name="ta" rows="6" style="width:340px;"> </textarea>
    	<br>
        <input type="text" name="countDisplay" size="3" maxlength="3" value="250"> Characters Remaining
    </form>
    
    <script type="text/javascript">  
    
    var form = document.getElementById('messageArea'),
        calcCharacters = form.elements.ta;
    
    calcCharacters.config = {
        maxChar: 250,
        counter: form.elements.countDisplay
    };
    
    calcCharacters.onkeyup =  function () {
        var config = this.config,
            x = config.maxChar - this.value.length;
        config.counter.value = x;
    }
    </script>
    </body> </html>

  17. #17
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by nichemtktg View Post
    you said. "This can then be further improved on, so that the config is not attached to the textarea, but instead is attached to the event function using a closure technique", but I don't see exactly how to apply the change you suggested. Can you say again the change you you were referring to?
    Sure. It involves a technique called closure, which is one of the things that makes JavaScript different from many other languages. The following article seems to do a good job of describing scopes and closures.
    Closure on JavaScript closures

    What we're going to do is to make use of the fact that every function creates a new activation object, which references all the function arguments and variables within the scope of that function. What is returned from this outer function is the inner function, which also knows about the variables from the outer function.

    Code javascript:
    function counterHandler(config) {
        return function () {
            ...
        };
    }

    This is very useful because functions assigned to events cannot have parameters to receive other variables. Since the returned function retains knowledge of other variables from the outer function, that means that you can call the counterHandler function with your config info, and the returned function (which retains that custom config) can be assigned to an event.

    Code javascript:
    calcCharacters.onkeyup = counterHandler({
        maxChar: 250,
        counter: form.countDisplay
    });

    All that's left now is cleaning up, where the contents of the inner function get their config info from the config variable.

    Code javascript:
    function counterHandler(config) {
        return function () {
            var x = config.maxChar - this.value.length;
            config.counter.value = x;
        };
    }
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  18. #18
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    You're missing the code that declares the form and calcCharacters variables.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •