-1

I am trying to animate the width of something when the .change() function is called, but it doesn't seem to be working.

Any idea why?

Here is my code:

$(document).ready(function(){
    $('#code').change(function(){
        //on change animate a width of +16px increase.
        $(this).animate({width: '+=16'});
    });
});

Here is a js fiddle with the issue recreated: http://jsfiddle.net/BUSSX/

IrfanM
  • 715
  • 3
  • 10
  • 21

5 Answers5

1

If based on your previous question HTML markup :

<button class="I button">I</button>
<button class="O button">O</button>

<input id="code" type="text" disabled />

So if you want to animate the width of the textbox, you need to animate it when click the button:

$('.button').click(function(event) {
    var text = $(this).text();
    $('input:text').val(function(index, val) {
        return val + text;
    });
    $('#code').animate({width: '+=16'});
});

Working Demo


If based on your above question HTML markup, you need to use keyup instead of change as well as include the jQuery library in the jsFiddle:

$(document).ready(function(){
    $('#code').keyup(function(){
        //on change animate a width of +16px increase.
        $(this).animate({width: '+=16'});
    });
}); 

Updated Demo


You just need to check which key was pressed:

$(document).ready(function(){
    $('#code').keyup(function(e){
        //on change animate a width of +16px increase.        
        if(e.keyCode == 8) { // Backspace pressed
            $(this).animate({width: '-=16'});
        } else {
            $(this).animate({width: '+=16'});
        }
    });
});

Updated Demo

Community
  • 1
  • 1
Eli
  • 14,779
  • 5
  • 59
  • 77
  • I need it to decrease in with if a character is deleted, too however. Right now when I delete a character after I type it, it increases. – IrfanM Apr 13 '13 at 04:18
1

If you really want a change event for input controls, then here's a jQuery plug-in method I wrote a little while ago that does this and works for nearly all ways that the content of the input control can be changed including drag/drop, copy/paste, typing, etc... It takes advantage of newer events that help with this if they exist, otherwise it falls back to listening for lots of other events and looking to see if the data has changed.

(function($) {

    var isIE = false;
    // conditional compilation which tells us if this is IE
    /*@cc_on
    isIE = true;
    @*/

    // Events to monitor if 'input' event is not supported
    // The boolean value is whether we have to 
    // re-check after the event with a setTimeout()
    var events = [
        "keyup", false,
        "blur", false,
        "focus", false,
        "drop", true,
        "change", false,
        "input", false,
        "textInput", false,
        "paste", true,
        "cut", true,
        "copy", true,
        "contextmenu", true
    ];
    // Test if the input event is supported
    // It's too buggy in IE so we never rely on it in IE
    if (!isIE) {
        var el = document.createElement("input");
        var gotInput = ("oninput" in el);
        if  (!gotInput) {
            el.setAttribute("oninput", 'return;');
            gotInput = typeof el["oninput"] == 'function';
        }
        el = null;
        // if 'input' event is supported, then use a smaller
        // set of events
        if (gotInput) {
            events = [
                "input", false,
                "textInput", false
            ];
        }
    }

    $.fn.userChange = function(fn, data) {
        function checkNotify(e, delay) {
            var self = this;
            var this$ = $(this);

            if (this.value !== this$.data("priorValue")) {
                this$.data("priorValue", this.value);
                fn.call(this, e, data);
            } else if (delay) {
                // The actual data change happens aftersome events
                // so we queue a check for after
                // We need a copy of e for setTimeout() because the real e
                // may be overwritten before the setTimeout() fires
                var eCopy = $.extend({}, e);
                setTimeout(function() {checkNotify.call(self, eCopy, false)}, 1);
            }
        }

        // hook up event handlers for each item in this jQuery object
        // and remember initial value
        this.each(function() {
            var this$ = $(this).data("priorValue", this.value);
            for (var i = 0; i < events.length; i+=2) {
                (function(i) {
                    this$.on(events[i], function(e) {
                        checkNotify.call(this, e, events[i+1]);
                    });
                })(i);
            }
        });
    }
})(jQuery);    

Then, your code would look like this:

$(document).ready(function(){
    $('#code').userChange(function(){
        //on change animate a width of +16px increase.
        $(this).animate({width: '+=16'});
    });
});

In looking at your code, you are increasing the width of the input control by 16px on every change. You probably should be looking at the number of characters in the control and assessing what to do about the width based on that because this will make things wider event if the user hits the backspace key. I'd probably do something like this that grows the item as content is added, but doesn't shrink it:

$(document).ready(function(){
    $('#code').userChange(function(){
        // on change animate width as chars are added
        // only grow it when the width needs to be larger than it is currently
        var item = $(this);
        var origWidth = item.data("initialWidth");
        var curWidth = item.width();
        if (!origWidth) {
            origWidth = curWidth;
            item.data("initialWidth", origWidth);
        }
        var newWidth = origWidth + (8 * item.val().length);
        if (newWidth > curWidth) {
            item.stop(true, true).animate({width: newWidth}, 500);
        }
    });

});

Working code example: http://jsfiddle.net/jfriend00/BEDcR/


If you want the userChange method to execute when you programmatically set the value with .val(), then you can make your own method for that:

$(document).ready(function(){
    function updateWidth() {
        // on change animate width as chars are added
        // only grow it when the width needs to be larger than it is currently
        var item = $(this);
        var origWidth = item.data("initialWidth");
        var curWidth = item.width();
        if (!origWidth) {
            origWidth = curWidth;
            item.data("initialWidth", origWidth);
        }
        var newWidth = origWidth + (8 * item.val().length);
        if (newWidth > curWidth) {
            item.stop(true, true).animate({width: newWidth}, 500);
        }
    }
    $('#code').userChange(updateWidth);

    $.fn.valNotify = function(value) {
        this.val(value);
        this.each(function() {
            updateWidth.call(this);
        });
        return this;
    }
});

Then, you can change your values with this and it will automatically resize too:

$("#code").valNotify("foo");
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I'm planning on inserting text inside the input, #code, using jQuery's .val() function. Like so `$('#code').val($('#code').val()+"O");` Is there a way I can make it increase in width by 16px each time I do that and then decrease to the original width if I do `$('#code').val('');` to clear the input? – IrfanM Apr 13 '13 at 04:59
  • @IrfanM - you will have to manually trigger the resize after using `.val()` because that doesn't trigger the change notification by design. If you want, you can implement a `.valNotify()` method that will set `.val()` and then trigger the resize. There are some browser-specific notifications when the value is programmatically changed, but no way to make those work cross browser other than triggering the change notification manually as I've described. Next time, you should do a better job of describing your actual requirements to get the answer you want. – jfriend00 Apr 13 '13 at 05:01
  • @IrfanM - I added one more code example with `.valNotify()`. Please edit your question to make it clear what you actually want. – jfriend00 Apr 13 '13 at 05:15
  • Okay, I'll write better questions from now on. Do I still have to use your plug in to use .valNotify()? – IrfanM Apr 13 '13 at 05:27
  • @IrfanM - if you don't care about resizing when typing happens or other user modifications of the `` element, then you don't need to use my `.userChange()` plugin. But, if you're not accepting user input, then one wonders why you don't just use a `` or `
    ` that resizes automatically and just set the `.innerHTML` on it. Resize would be entirely automatic.
    – jfriend00 Apr 13 '13 at 05:29
  • @IrfanM - also see this previous post: http://stackoverflow.com/questions/1288297/jquery-auto-size-text-input-not-textarea – jfriend00 Apr 13 '13 at 05:31
  • hmm interesting. Thank you for sharing. I'm quite sorry if i wasn't clear. I was just trying to be specific so it didn't seem like my question was too broad. – IrfanM Apr 13 '13 at 05:32
  • @IrfanM - but you left out the part that you want to do the resize when you call `.val()` and that required an entirely different answer than the user typing into the field. Anyway, hope you got what you need now. – jfriend00 Apr 13 '13 at 05:34
  • Thank you. I thought I did, because the .valNotify() code made sense when I read it. But when I run it, it doesn't work. The text is not transferred into the input nor does it resize. Here is the code I am using: https://gist.github.com/theirf/5377131 – IrfanM Apr 13 '13 at 05:36
  • @IrfanM - I fixed a typo in the definition of `.valNotify`. It needed to be `$.fn.valNotify = function ...` – jfriend00 Apr 13 '13 at 05:42
  • Here is a js fiddle of the code, it is still not working: http://jsfiddle.net/zT4uD/ – IrfanM Apr 13 '13 at 05:48
  • @IrfanM - lots of problems with your jsFiddle implementation. Here's a working one: http://jsfiddle.net/jfriend00/XwxxS/. – jfriend00 Apr 13 '13 at 05:55
0

You forgot to load jQuery, working fine here http://jsfiddle.net/BUSSX/13/ - also you need the click event. Or even better use the keyup event so that as soon as something is typed, the textbox increases in width - http://jsfiddle.net/BUSSX/15/

Rishabh
  • 1,901
  • 2
  • 19
  • 18
  • The fiddle is not working fine for me. I don't see the input increasing. – IrfanM Apr 13 '13 at 03:34
  • If you add some text in the second link, the input will increase in width :) – Rishabh Apr 13 '13 at 03:34
  • Oh, okay. I was just clicking the button. – IrfanM Apr 13 '13 at 03:35
  • remember `change` only works when you have changed the contents and then de-focused the input, i.e., on change + `blur`. – Rishabh Apr 13 '13 at 03:36
  • If you want to make it work on clicking the button then attach a `click` event handler on the button. – Rishabh Apr 13 '13 at 03:36
  • well, I am going to be typing text in the input using jQuery's .val function. not through the keyboard. How can the input's width increase when jQuery has added to the value of it using .val()? – IrfanM Apr 13 '13 at 03:37
0

IrfanM, instead of incrementing by a fixed amount, you might consider incrementing by just the right amount to accommodate each character as it is typed.

Unless I've overcomplicated things (not completely unknown), this is moderately tricky.

In the following jQuery plugin :

  • text input fields are each given a hidden <span> with the same font-family and font-size as its respective input element.
  • the <span> elements act as "measuring sticks" by accepting a copy of their input field's entire text every time a character is typed.
  • the width of the <span> plus one generous character width is then used to determine the width of the input field.

Here's the code :

(function ($) {
    var pluginName = 'expandable';
    $.fn[pluginName] = function () {
        return this.each(function (i, input) {
            var $input = $(input);
            if (!$input.filter("input[type='text']").length) return true;

            // Common css directives affecting text width
            // May not be 100% comprehensive
            var css = {
                fontFamily: $input.css('fontFamily'),
                fontSize: $input.css('fontSize'),
                fontStyle: $input.css('fontStyle'),
                fontVariant: $input.css('fontVariant'),
                fontWeight: $input.css('fontWeight'),
                fontSizeAdjust: $input.css('fontSizeAdjust'),
                fontStretch: $input.css('fontStretch'),
                letterSpacing: $input.css('letterSpacing'),
                textTransform: $input.css('textTransform'),
                textWrap: 'none'
            };
            var $m = $("<span/>").text('M').insertAfter($input).css(css).text('M').hide();
            var data = {
                'm': $m,
                'w': $m.width()
            };
            $input.data(pluginName, data).keyup(function (e) {
                $this = $(this);
                var data = $this.data(pluginName);
                var w = data.m.html($this.val().replace(/\s/g, "&nbsp;")).width();
                $this.css({
                    'width': w + data.w
                });
            }).trigger('keyup');
        });
    };
})(jQuery);

$(document).ready(function () {
    $('input').expandable();
});

DEMO

This works because a <span> element automatically expands to accommodate its text, whereas an <input type="text"> element does not. A great feature of this approach is that the keystrokes don't need to be tested - the plugin automatically responds to character deletions in the same way it responds to character strokes.

It works with proportional and monospaced fonts and even responds appropriately to cut and paste.

The only precaution necessary is to convert spaces to non-breaking spaces, $nbsp;, otherwise HTML renders multiple spaces as a single space in the <span> element.

Of course, it you really want exactly 16px growth for every keystroke, then stick with what you already have.

Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
0

you have a bad implementation check http://jsfiddle.net/3dSZx/ and you need add jquery to fiddle

JS

$(document).ready(function(){
    $('#push').click(function(){
        //on change animate a width of +16px increase.
        $('#code').animate({ width: '+=16'});
    });    
});
rkmax
  • 17,633
  • 23
  • 91
  • 176