Backbone Save-Once e Collection.saveAll ()

leia mais em: Blog de Ben Roux

Backbone.js faz muitas coisas certas quando se trata de interfaces com clientes pesados. MVController do lado do cliente, RESTful por design e localizações de código estruturado são apenas alguns dos benefícios que aponto como razões para seu uso. Mas, assim como o número da versão (0.9.2 no momento desta escrita) sugere, ainda há algumas coisas por vir.

Salvando no Backbone.Js

Backbone.js é projetado para salvamentos incrementais de objetos. Ou seja, quando um usuário faz uma alteração ou uma série de alterações no site, essas alterações são postadas de volta no servidor de forma assíncrona e geralmente são invisíveis para o usuário. Na minha opinião, este é um ótimo conceito: os usuários nunca se esquecem de pressionar o botão Salvar e dificilmente, ou nunca, esperam que as páginas sejam recarregadas. Isso proporciona o que parece ser uma experiência de usuário ideal.

O problema…

Ocasionalmente, maquetes ou sistemas exigem o fluxo de trabalho mais tradicional: os usuários interagem com uma página por algum tempo e, a seguir, pressionam o botão Enviar padrão na parte inferior. Se a interface for pesada do lado do cliente, normalmente procuro o Backbone. O problema surge quando se trata de salvar os objetos. Onde você se encontra é um lugar onde você escreve algum código:

var PostsCollection = Backbone.Collection.extend({
model
: post,

saveAll
: function( ) {
// Loop over my collection...
_
(this.models).each( function(post) {
// And POST for each object in the collection
post
.save();
} );
}
}

Existem algumas desvantagens claras para isso. O maior deles é o perigo de perda de dados. O segundo maior é a confusão do usuário sobre o que está acontecendo enquanto o sistema leva um tempo para fazer o POST um número arbitrário de vezes para o servidor.

Uma solução menos que ideal

O truque que usei nesses casos é confiar no Backbone para a interface e depois voltar ao HTML padrão para o resto. Para fazer isso, você simplesmente reescreve sua saveALLfunção para se comportar de maneira diferente:

saveAll: function( ) {
// Create the submission form
var form = document.createElement( 'form' );
form
.setAttribute( "method", 'POST' )
form
.setAttribute( 'action', window.location.pathname );

// Jsonify all of the models in the collection
var formData = []
_
(this.models).each( function(post) {
formData
.push( post.toJSON() );
} );
formData
= JSON.stringify( formData );

// Store the array in a hidden field
var hidden = document.createElement( 'input' );
hidden
.setAttribute( 'type', 'hidden' );
hidden
.setAttribute( 'name', 'data' );
hidden
.setAttribute( 'value', formData );
form
.appendChild( hidden );

// Save to the server.
form
.submit();
}

Aqui, temos uma experiência de usuário mais padrão. Quando chamamos o saveAllem um clique de Enviar , eles veem o carregamento do navegador e a página se comportando como se fosse um formulário normal. Não há necessidade de elementos extras da interface do usuário ou indicadores de que a página está “fazendo algo”. Não há necessidade de tentar validar que você recebeu todos os POSTs do usuário.

Próximos passos

Como mencionei, essa solução é menos do que ideal. Realmente, eu gostaria de deixar de criar elementos dom e realmente trabalhar exclusivamente com objetos mais leves como XMLHttpRequest e FormData . No entanto, os métodos de teste com esses objetos pareciam resultar em corpos POST complicados, o que tornava o manuseio do lado do servidor bastante desagradável. Limpar a solicitação seria uma grande vantagem quando se tratasse de simplificar o javascript.

Estou muito aberto a ideias se alguém mais se deparar com esse problema e resolvê-lo de uma maneira diferente.