0

I've created a number-only input validator for my app that's using KnockoutJS. When the user presses an illegal key (letter) I want the target input to flash the CSS animation on each illegal keypress. As it currently stands it just fires the animation once and I'm not sure why.

Example: http://codepen.io/anon/pen/oIamG/

Anyone any ideas?

4
  • Think I've identified the problem but not yet the solution: the removeClass element isnt firing - so the animation cant happen again. Look in Chrome Dev Tools and inspect the input field during the firing of the event; you'll see what Im talking about. Commented Apr 19, 2014 at 17:03
  • @staypuftman you're totally right, I'd seen that in my local copy but I just thought it was me going mad. Commented Apr 19, 2014 at 17:08
  • I don't know knockout (learning Ember myself ;) but maybe knockout uses 'then' and promises somehow. I'm just learning promises but this seems exactly like where they would come into play. Knockout's documentation has a little bit on it: knockoutjs.com/documentation/unobtrusive-event-handling.html Commented Apr 19, 2014 at 17:21
  • I gotta hit the gym but I'm curious about this, as it maps to what I'm doing in Ember. If the promise thing turns out right, post an answer here and I'll try and understand what you did. Commented Apr 19, 2014 at 17:23

1 Answer 1

1

The problem is that you need to reset you CSS animation. In order to do that, you'd need to remove the animation and then add it again.
Move the -webkit-animation properties to the input like

input {
    border: 2px solid black;
    padding: 8px;
    /* 0.2s is used, just to see the effect, the animation needs to be  */
    -webkit-animation-duration: 0.2s;
    -webkit-animation-direction:forwards;
    -webkit-animation-timing-function:ease-in-out;
}

@-webkit-keyframes inputValidationBorder {
    0% { border: 2px solid red; }
    100% { border: 2px solid black; }
}

Then use the following binding:

ko.bindingHandlers.numeric = {
    init: function (element, valueAccessor) {
        $(element).bind('webkitAnimationEnd', function(){
            this.style.webkitAnimationName = '';
        });

        $(element).on('keydown', function (event) {
            // allow backspace, delete, tab, escape, enter/return and period.
            // if input is a letter then disable keypress
            if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96    || event.keyCode > 105)) {
               element.style.webkitAnimationName= 'inputValidationBorder'; 
               event.preventDefault();
            }
        });
    }
};
Sign up to request clarification or add additional context in comments.

3 Comments

here is a working example. I'd also like to point out that while filtering on event.keyCode, users can still enter ALT+_number_ which don't get caught by your if-statement.
@MajorByte Can you explain what you did here a little more clearly for me? It looks like you have used 'this' instead of passing the event parameter into the function - what's the rationale here?
First off, and maybe obvious, the function .bind() is jQuery's and not KnockoutJS'. With that out of the way, this is the element on which the webkitAnimationEnd event is triggered. I could have used an event parameter in that function and do event.originalEvent.target.style.webkitAnimationName = '' instead. This is shorter and I know it's the element presented/selected by $(element) .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.