6

I have a Model that has 1 input. Also, I have a Collection. Now, when I add a model to the collection, I want to set the focus to it's input. To be precise, I need to set the focus on the newly created model view's input.

However, I can't seem to get it to work. Here's my function that adds the model's view to the collection view:

addOne: function(InvoiceItem) {
    var view = new InvoiceItemView({model: InvoiceItem});
    this.$('tr[data-id="'+InvoiceItem.get('after')+'"]').after(view.render().el);
    this.$('tr[data-id="'+InvoiceItem.cid+'"]').css('background', 'green');
    this.$('tr[data-id="'+InvoiceItem.cid+'"] input').focus();
},

The problem is, the third call: this.$('tr[data-id="'+InvoiceItem.cid+'"] input').focus(); does not do anything. And it's weird, because it seems that I can only do DOM manipulation on the root element tr, and on nothing else besides that.

It seems to me that jQuery doesn't know that the element exists, which is weird, because when I do alert(this.$('tr[data-id="'+InvoiceItem.cid+'"] input').length) I get 1, which indicates that the element exists.

What it is that I am doing wrong here?

mu is too short
  • 426,620
  • 70
  • 833
  • 800
ragulka
  • 4,312
  • 7
  • 48
  • 73

3 Answers3

21

Using _.defer fixed my problem:

var $this = this;
_.defer(function(){
  $this.$('tr[data-id="'+InvoiceItem.cid+'"] input').focus();
});
jeroen.verhoest
  • 5,173
  • 2
  • 27
  • 27
2

Instead of this.$('tr[data-id="'+InvoiceItem.cid+'"] input').focus();

try this

$(view.render().el).find('input').focus();
Paul
  • 18,349
  • 7
  • 49
  • 56
  • Doesn't seem to work and I think I know why: the collection view gets re-rendered because the collection changes once I add the item to the view. And re-rendering loses focus from any input... Is there a way to restore the focus after re-render? – ragulka Jan 09 '12 at 15:52
  • My first guess was that it's because the collection view gets re-rendered, but that doesn't seem to be the case (I tried with simple alert() to see if the render gets triggered). It's weird because even if i do just $('input').hide() - it doesn't do anything. EDIT: actually it seems that occasionally, after a certai amount of time has passed, it seems to hide the first row's input – ragulka Jan 09 '12 at 15:59
  • @ragulka Can you share your collection, model and view code. There's probably some events firing that's causing it – Paul Jan 09 '12 at 21:06
2

I had a problem very similar to yours and ended up here while searching for a solution. Your post was a few months ago so you probably have moved past this, but hopefully this will help someone else. I was able to solve the problem using jQuery's ready function handler. I always thought it could only be used on the document but you can use it on subnodes as well. Try this:

addOne: function(InvoiceItem) {
  var view = new InvoiceItemView({model: InvoiceItem});
  $('tr[data-id="'+InvoiceItem.get('after')+'"]').ready(function(){
    $('tr[data-id="'+InvoiceItem.cid+'"]').css('background', 'green');
    $('tr[data-id="'+InvoiceItem.cid+'"] input').focus();
  });
  $('tr[data-id="'+InvoiceItem.get('after')+'"]').after(view.render().el);
chad
  • 21
  • 4
  • Although it can be used on subnodes, it won't wait for subnodes to become ready, but just *wait for the DOM become **safe** to manipulate*. This has exactly the same effect of $`(function(){console.log('ready')})` – motobói Sep 11 '16 at 18:20