Backbone.js-Backbone.sync 또는 jQuery.ajax에 전체 컬렉션을 저장하는 방법은 무엇입니까?


81

나는 그것을 할 수 있다는 것을 잘 알고 있으며 꽤 많은 곳을 살펴 보았습니다 (포함 : 전체 컬렉션 저장을위한 모범 사례? ). 하지만 여전히 "정확히 어떻게"코드로 작성되었는지 확실하지 않습니다. (게시물은 영어로 설명합니다. 자바 스크립트에 대한 설명이 있으면 좋겠습니다. :)

모델 컬렉션이 있다고 가정 해 보겠습니다. 모델 자체에 중첩 컬렉션이있을 수 있습니다. 부모 컬렉션의 toJSON () 메서드를 재정의했으며 유효한 JSON 개체를 얻고 있습니다. 전체 컬렉션 (해당 JSON)을 "저장"하고 싶지만 백본에는 해당 기능이 내장되어 있지 않은 것 같습니다.

var MyCollection = Backbone.Collection.extend({
model:MyModel,

//something to save?
save: function() {
   //what to write here?
 }

});

나는 당신이 말해야 할 곳을 알고 있습니다.

Backbone.sync = function(method, model, options){
/*
 * What goes in here?? If at all anything needs to be done?
 * Where to declare this in the program? And how is it called?
 */
}

처리와 함께 '보기'가 완료되면 컬렉션이 서버에 자신을 "저장"하도록 지시하는 역할을합니다 (대량 업데이트 / 생성 요청 처리 가능).

발생하는 질문 :

  1. "모두 함께 연결"하기 위해 코드를 작성하는 방법 / 무엇입니까?
  2. 콜백의 '올바른'위치는 무엇이며 "성공 / 오류"콜백을 지정하는 방법은 무엇입니까? 내 말은 문법적으로? 백본에 콜백을 등록하는 구문이 명확하지 않습니다 ...

실제로 까다로운 작업이라면 뷰 내에서 jQuery.ajax를 호출 하고 성공 / 오류 콜백으로 this.successMethod또는 전달할 수 있습니까 this.errorMethod?? 작동할까요?

백본의 사고 방식과 일치해야합니다. 전체 컬렉션을 동기화하는 것이 확실히 누락 된 것을 알고 있습니다.


서버 측 코드가 이것을 단일 요청으로 취할 수 있습니까? 즉, 전체 최상위 컬렉션, 모든 모델 및 중첩 된 컬렉션을 단일 JSON 패킷으로? 아니면 각 모델을 개별적으로 저장해야합니까? 편집 : 아, 자세히 읽어보십시오. 서버는 "대량 업데이트 / 생성"이 가능합니다
Edward M Smith

@ 에드워드 : 네! 일반적으로 우려 사항이기 때문에 명시 적으로 작성했지만이 경우에는 그렇지 않습니다. :)
PhD

그렇다면 서버가받을 것으로 예상하는 데이터의 구조는 무엇입니까?
Edward M Smith

@Edward : 데이터 구조가 중요합니까? 주석에서 서식을 지정할 수는 없지만 다음과 같습니다. [{postId : 1, labels : [{id : 1, name : "a"}, {id : 2, name : "b"}]}] 기본적으로 각 " postId "는 자체적으로 객체 인 레이블 세트 / 배열을 가질 수 있습니다. 그런 게시물이 많이있을 수 있습니다 ... 뭔가 빠뜨리지 않는 한 데이터 형식이 당면한 문제와 아무 관련이 없다고 생각합니다
PhD

답변:


64

내 즉각적인 생각은 Backbone.Collection의 save 메서드에 대한 메서드를 재정의하는 것이 아니라 컬렉션을 다른 Backbone.Model에 래핑하고 toJSON 메서드를 재정의하는 것입니다. 그러면 Backbone.js는 모델을 단일 리소스로 취급하므로 backone이 너무 많이 생각하는 방식을 해킹 할 필요가 없습니다.

Backbone.Collection에는 toJSON 메서드가 있으므로 대부분의 작업이 수행됩니다. 래퍼 Backbone.Model의 toJSON 메서드를 Backbone.collection에 프록시하면됩니다.

var MyCollectionWrapper = Backbone.Model.extend({
url: "/bulkupload",

//something to save?
toJSON: function() {
    return this.model.toJSON(); // where model is the collection class YOU defined above
 }

});

3
나는 소스 코드를 보면서 컬렉션이 보인다 않는 최우선은 문제가되지 않습니다 그래서 훨씬 쉽게 :) 될 방법 세계 막아을 한 경우에 (, 방법 선방이
박사

래퍼 아이디어에 +1-깨끗하고 달콤합니다. 전혀 생각하지 않았습니다. Backboard.sync를 직접 호출하고 "model"인수 대신 컬렉션을 전달해야 할 수도 있다고 생각했습니다. 그래도 작동하려면 모델의 URL을 지정해야합니까 ... 어떤 생각이 있습니까? sync 메소드는 내부적으로 getURL(model)모델 인수를 호출 하고 어떤 유형의 비교도 수행하지 않기 때문에 ... 의도적으로 설계된 것 같습니다
PhD

3
동의-매우 우아합니다. 그러나이 솔루션에 문제가 있습니다. 내 래퍼 모델은 항상 새롭기 때문에 save ()하면 항상 POST입니다. 이미 데이터를 검색 했으므로 save ()하면 PUT이어야합니다. isNew () = false를 하드 코딩하거나 가짜 ID를 설정할 수 있다고 생각하지만 이것은 우아한 해결책처럼 보이지 않습니다. 의견 있으십니까?
Scott Switzer 2013 년

1
정말 깨끗한 대답, CollectionWrapper를 인스턴스화하는 방법을 보는 것이 좋을 것입니다.
Anthony

예, 저에게도 효과가 있었고 좋은 노력에 +1했지만 두 개의 컬렉션을 서버로 보내고 싶다면 어떻게해야합니까?
CodeNotFound jul.

25

아주 간단합니다 ...

Backbone.Collection.prototype.save = function (options) {
    Backbone.sync("create", this, options);
};

... 컬렉션에 저장 방법을 제공합니다. 변경 사항에 관계없이 항상 모든 컬렉션의 모델을 서버에 게시합니다. 옵션은 일반적인 jQuery ajax 옵션입니다.


4
맞아요. return Backbone.sync..더 많은 Backbonish 가 추가 될 수 있습니다 .
yves amsellem 2013 년

나는-유형에 대해-업데이트가 만드는 것보다 낫다고 생각합니다. 모델 또는 컬렉션의 toJSON을 재정의 할 수 있으므로 서버로 보낼 내용을 규제 할 수 있습니다 ... (일반적으로 필요한 id 속성 만) Backbone.Relational에서 json 형식에 추가 할 내용도 설정할 수 있습니다.
inf3rno

1
Backbone.sync는 페이지의 "생성"기대 backbonejs.org/docs/backbone.html#section-141을
hacklikecrack

8

나는 'save'와 같은 메소드를 가지게되었고 그 안에서 $ .ajax를 호출했습니다. @brandgonesurfing이 제안한대로 래퍼 클래스를 추가 할 필요없이 더 많은 제어권을 얻었습니다 (아이디어를 절대적으로 좋아하지만 :) 이미 collection.toJSON () 메서드를 재정의했기 때문에 언급했듯이 모든 작업을 수행하는 것입니다. 아약스 호출에서 ...

이것이 그것을 우연히 발견하는 사람에게 도움이되기를 바랍니다 ...


3
Backbone.ajax를 호출하는 것이 더 나을 것입니다 (어쨌든 jQuery에 프록시되지만 유지 관리가 더 쉬워집니다)
developerbmw

5

이것은 실제로 클라이언트와 서버 간의 계약에 따라 다릅니다. 다음은 PUT to /parent/:parent_id/childrenwith {"children":[{child1},{child2}]}가 부모의 자식을 PUT에 있는 것으로 대체하고 반환 하는 간단한 CoffeeScript 예제입니다 {"children":[{child1},{child2}]}.

class ChildElementCollection extends Backbone.Collection
  model: Backbone.Model
  initialize: ->
    @bind 'add', (model) -> model.set('parent_id', @parent.id)

  url: -> "#{@parent.url()}/children" # let's say that @parent.url() == '/parent/1'
  save: ->
    response = Backbone.sync('update', @, url: @url(), contentType: 'application/json', data: JSON.stringify(children: @toJSON()))
    response.done (models) => @reset models.children
    return response

이것은 매우 간단한 예입니다. 더 많은 작업을 수행 할 수 있습니다. 실제로 save ()가 실행될 때 데이터가 어떤 상태인지, 서버로 전달하기 위해 필요한 상태가 무엇인지, 서버가 제공하는 내용에 따라 다릅니다. 뒤.

서버가 PUT로 [{child1},{child2]정상이면 Backbone.sync 행이 response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json').


옵션의 속성은 "URL이") = 여기이 켜지지하지 않습니다
세르게이 Kamardin

5

대답은 서버 측에서 컬렉션으로 수행하려는 작업에 따라 다릅니다.

게시물과 함께 추가 데이터를 보내야 하는 경우 래퍼 모델 또는 관계형 모델 이 필요할 수 있습니다 .

으로 래퍼 모델 당신은 항상 당신의 자신의 작성해야 구문 분석 방법 :

var Occupants = Backbone.Collection.extend({
    model: Person
});

var House = Backbone.Model.extend({
    url: function (){
        return "/house/"+this.id;
    },
    parse: function(response){
        response.occupants = new Occupants(response.occupants)
        return response;
    }
});

관계형 모델 은 더 쉽게 구성 할 수 있고나머지 서비스로 보내는 json에 속성을 넣을 includeInJSON 옵션으로조절할수 있기 때문에 더 좋습니다.

var House = Backbone.RelationalModel.extend({
    url: function (){
        return "/house/"+this.id;
    },
    relations: [
        {
            type: Backbone.HasMany,
            key: 'occupants',
            relatedModel: Person,
            includeInJSON: ["id"],
            reverseRelation: {
                key: 'livesIn'
            }
        }
    ]
});

추가 데이터를 보내지 않으면 컬렉션 자체를 동기화 할 수 있습니다 . 이 경우 컬렉션 (또는 컬렉션 프로토 타입)에 저장 메서드 를 추가해야합니다 .

var Occupants = Backbone.Collection.extend({
    url: "/concrete-house/occupants",
    model: Person,
    save: function (options) {
        this.sync("update", this, options);
    }
});

3

또한 Backbone 컬렉션에 내장 저장 기능이 없다는 사실에 놀랐습니다. 이를 위해 백본 컬렉션에 넣은 내용은 다음과 같습니다. 컬렉션의 각 모델을 반복하고 독립적으로 저장하고 싶지는 않습니다. 또한 Node를 사용하는 백엔드에서 Backbone을 사용하고 있으므로 네이티브 Backbone.sync를 재정 의하여 소규모 프로젝트의 플랫 파일에 저장하지만 코드는 거의 동일해야합니다.

    save: function(){                                                                                                                                                                                                                                                                                                                                                     
      Backbone.sync('save', this, {                                                                                                                                                                                                                                                                                                                                     
        success: function(){                                                                                                                                                                                                                                                                                                                                          
          console.log('users saved!');                                                                                                                                                                                                                                                                                                                              
        }                                                                                                                                                                                                                                                                                                                                                             
      });                                                                                                                                                                                                                                                                                                                                                               
    }

차종은 같은에 옵션을 전달 너무 감지save: function (options) { Backbone.sync('save', this, options); }
매트 플레처

3

내가 아는 오래된 스레드는 다음과 같습니다.

Backbone.Collection.prototype.save = function (options) {
            // create a tmp collection, with the changed models, and the url
            var tmpCollection = new Backbone.Collection( this.changed() );
            tmpCollection.url = this.url;
            // sync
            Backbone.sync("create", tmpCollection, options);
        };
        Backbone.Collection.prototype.changed = function (options) {
            // return only the changed models.
            return this.models.filter( function(m){
                return m.hasChanged()
            });
        };
// and sync the diffs.
self.userCollection.save();

앞쪽으로 꽤 긴장 :)


2

다음은 간단한 예입니다.

var Books = Backbone.Collection.extend({
model: Book,
url: function() {
  return '/books/';
},
save: function(){
  Backbone.sync('create', this, {
    success: function() {
      console.log('Saved!');
    }
  });
 }
});

컬렉션에서 save () 메서드를 호출하면 정의 된 URL로 PUT 메서드 요청을 보냅니다.


내 컬렉션 저장 문제를 해결하는 데 도움이 될 수 있는지 궁금합니다. 지금 jsfiddle.net/kyllle/f1h4cz7f/3 toJSON ()은 각 모델을 업데이트하지만 저장에 데이터가없는 것 같습니다.
styler

1

나는 다음과 같은 것을 시도 할 것입니다.

var CollectionSync = function(method, model, [options]) {
    // do similar things to Backbone.sync
}

var MyCollection = Backbone.Collection.extend({
    sync: CollectionSync,
    model: MyModel,
    getChanged: function() {
        // return a list of models that have changed by checking hasChanged()
    },
    save: function(attributes, options) {
        // do similar things as Model.save
    }
});

( https://stackoverflow.com/a/11085198/137067 )


1

허용되는 대답은 꽤 좋지만 한 단계 더 나아가 리스너에 대해 적절한 이벤트가 발생하는지 확인하는 동시에 옵션 ajax 이벤트 콜백을 전달할 수있는 코드를 제공 할 수 있습니다.

save: function( options ) {
  var self = this;

  var success = options.success;
  var error = options.error;
  var complete = options.complete;

  options.success = function( response, status, xhr ) {
    self.trigger('sync', self, response, options);
    if (success) return success.apply(this, arguments);
  };

  options.error = function( response, status, xhr ) {
    self.trigger('error', self, response, options);
    if (error) return error.apply(this, arguments);
  };

  options.complete = function( response, status, xhr ) {
    if (complete) return complete.apply(this, arguments);
  }

  Backbone.sync('create', this, options);
}

0

2017 년에 여전히 backbone.js를 사용하는 사람에게는 허용되는 답변이 작동하지 않습니다.

래퍼 모델에서 toJSON () 재정의를 제거하고 모델 래퍼를 인스턴스화 할 때 컬렉션에서 toJSON을 호출 해보세요.

new ModelWrapper(Collection.toJSON());
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.