Динамічне встановлення id та className у поданнях Backbone.js


85

Я в процесі вивчення та використання Backbone.js.

У мене є модель товару та відповідний вигляд товару. Кожен екземпляр моделі має атрибути item_class та item_id, які я хочу відображати як атрибути 'id' та 'class' відповідного подання. Який правильний спосіб цього досягти?

Приклад:

var ItemModel = Backbone.Model.extend({      
});

var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});

var ItemView = Backbone.View.extend({       
});

Як я повинен реалізувати подання, щоб перегляди переклались на:

<div id="id1" class="nice"></div>
<div id="id2" class="sad"> </div>

У більшості прикладів, які я бачив, вигляд el служить безглуздим елементом-обгорткою, всередині якого потрібно вручну написати «семантичний» код.

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...

   render: function() {
     $(this.el).html("<div id="id1" class="nice"> Some stuff </div>");
   }       
});

Отже, при отриманні, хтось отримує

<div> <!-- el wrapper -->
    <div id="id1" class="nice"> Some stuff </div>
</div>

Але це здається марним - навіщо зовнішній div? Я хочу, щоб el переклав безпосередньо у внутрішній div!

Відповіді:


133

Короткий зміст: динамічно встановлюються атрибути подання з даними моделі

http://jsfiddle.net/5wd0ma8b/

// View class with `attributes` method
var View = Backbone.View.extend( {
  attributes : function () {
    // Return model data
    return {
      class : this.model.get( 'item_class' ),
      id : this.model.get( 'item_id' )
    };
  }
  // attributes
} );

// Pass model to view constructor
var item = new View( {
  model : new Backbone.Model( {
    item_class : "nice",
    item_id : "id1"
  } )
} );
  • Цей приклад передбачає, що ви дозволяєте Backbone генерувати для вас елемент DOM.

  • attributesМетод викликається після того, як властивості , що передаються вид конструктора встановлюються (в даному випадку model), що дозволяє динамічно встановлювати атрибути з модельними даними , перш ніж створює Backbone el.

  • На відміну від деяких інших відповідей: не жорстко кодує значення атрибутів у класі представлення, динамічно встановлює їх із даних моделі; не чекає, поки render()встановить attr vals; не встановлює неодноразово attr vals під час кожного дзвінка render(); не надмірно встановлює вручну значення attr для елемента DOM.

  • Зверніть увагу, що при встановленні класу під час виклику Backbone.View.extendабо конструкторі подання (наприклад new Backbone.View), ви повинні використовувати ім'я властивості DOM className, але якщо його встановлюватиattributes хеш / методу (як в цьому прикладі) , ви повинні використовувати ім'я атрибута, class.

  • Станом на Backbone 0.9.9:

    При оголошенні View ... el, tagName, idіclassName тепер можуть бути визначені як функції, якщо ви хочете їх значення повинні бути визначені під час виконання.

    Я згадую це на випадок ситуації, коли це було б корисно як альтернатива використанню attributes методу, як показано.

Використання існуючого елемента

Якщо ви використовуєте існуючий елемент (наприклад, перехід elдо конструктора подання) ...

var item = new View( { el : some_el } );

... тоді attributesне буде застосовано до елемента. Якщо бажані атрибути не встановлені на елементі, або ви не хочете , щоб дублювати дані в своєму класі виду і інше місце, то ви можете додати initializeметод у вашому виді конструктора , який відноситься attributesдо el. Щось на зразок цього (за допомогою jQuery.attr):

View.prototype.initialize = function ( options ) {
  this.$el.attr( _.result( this, 'attributes' ) );
};

Використання el , візуалізація, уникаючи обгортки

У більшості прикладів, які я бачив, вигляд el служить безглуздим елементом-обгорткою, всередині якого потрібно вручну написати «семантичний» код.

Немає жодної причини view.elбути "безглуздим елементом обгортки". Насправді це часто порушує структуру DOM. Якщо клас представлення представляє <li>елемент, наприклад, його потрібно відобразити як <li>- візуалізація як як <div>або будь-якого іншого елемента порушить модель вмісту. Швидше за все , ви хочете зосередитися на правильному налаштуванні елемента вашої точки зору (використовуючи властивості , як tagName, classNameі id) , а потім робить його зміст в подальшому.

Варіанти, як забезпечити взаємодію об’єктів вигляду Backbone із DOM, широко відкриті. Є 2 базові початкові сценарії:

  • Ви можете приєднати існуючий елемент DOM до подання Backbone.

  • Ви можете дозволити Backbone створити новий елемент, який відключений від документа, а потім якось вставити його в документ.

Існують різні способи генерування вмісту для елемента (встановіть літеральний рядок, як у вашому прикладі; використовуйте бібліотеку шаблонів, як Вуса, Ручки тощо). Як слід використовуватиel властивість подання, залежить від того, що ви робите.

Існуючий елемент

Ваш приклад рендерингу передбачає, що у вас є існуючий елемент, який ви призначаєте поданню, хоча ви не показуєте екземпляра подань. Якщо це так, і елемент уже є в документі, можливо, ви захочете зробити щось подібне (оновіть вміст el, але не змінюйте elйого):

render : function () {
  this.$el.html( "Some stuff" );
}

http://jsfiddle.net/vQMa2/1/

Сформований елемент

Скажімо, у вас немає існуючого елемента, і ви дозволяєте Backbone згенерувати його для вас. Ви можете хотіти зробити що - щось подібне (але це, ймовірно , краще Архітектор речі , так що ваша думка не несе відповідальності за знання про себе нічого зовні):

render : function () {
  this.$el.html( "Some stuff" );
  $( "#some-container" ).append( this.el );
}

http://jsfiddle.net/vQMa2/

Шаблони

У моєму випадку я використовую шаблони, наприклад:

<div class="player" id="{{id}}">
<input name="name" value="{{name}}" />
<input name="score" value="{{score}}" />
</div>
<!-- .player -->

Шаблон представляє повний вигляд. Іншими словами, навколо шаблону не буде обгортки - div.playerце буде корінь або найвіддаленіший елемент мого подання.

Мій клас гравців буде виглядати приблизно так (на дуже спрощеному прикладі render()):

Backbone.View.extend( {
  tagName : 'div',
  className : 'player',

  attributes : function () {
    return {
      id : "player-" + this.model.cid
    };
  },
  // attributes

  render : function {
    var rendered_template = $( ... );

    // Note that since the top level element in my template (and therefore
    // in `rendered_template`) represents the same element as `this.el`, I'm
    // extracting the content of `rendered_template`'s top level element and
    // replacing the content of `this.el` with that.
    this.$el.empty().append( rendered_template.children() );
  }      
} );

Чудовий спосіб переписати властивість атрибутів функцією і повернути об’єкт знову!
Kel

2
@Kel, так, це хороший спосіб виконати щось динамічне, наприклад те, що запитує запитання, заповнюючи атрибути даними моделі, без необхідності використовувати повторюваний код там, де подаються екземпляри. Ви, напевно, це знаєте, але на випадок, якщо це не очевидно, це особливість Backbone, що ви можете використовувати функцію, яка повертає хеш як значення attributes, як і ряд інших властивостей Backbone, які можуть бути надані як функція або деякі інші тип вартості. У цих випадках Backbone перевіряє, чи є значення функцією, викликає її та використовує повернене значення.
JMM

95

На ваш погляд, просто зробіть щось подібне

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...

   render: function() {
     $(this.el).attr('id', 'id1').addClass('nice').html('Some Stuff'); 
   }       
});

Це правильна відповідь на це Питання, і його слід прийняти
reach4thelasers

13
Ця відповідь не демонструє динамічного встановлення атрибутів подання на основі даних моделі, вона просто показує альтернативний метод жорсткого кодування значень атрибутів.
JMM

3
@JMM - Його зразок коду також не використовує дані моделі. Ця відповідь працює на основі його зразка коду. Очевидно, що дані моделі можна замінити значеннями.
Клінт

5
@Clint, я б не розраховував на те, що це буде очевидним для ОП. "Його зразок коду також не використовує дані моделі." - це тому, що він не знає, як, а отже, і чому він попросив допомоги. Мені здається зрозумілим, що він запитує, як встановити атрибути view.el, використовуючи дані моделі, і не знає, як це робити. Відповідь навіть не показує, як це зробити, і чому б вам дочекатися, поки рендерінг все одно зробить це, або робити це знову щоразу, коли ви робите? "Ця відповідь працює ..." - як це працює? Кожен створений таким чином погляд мав би однакові атрибути. Єдине, що це показує, це як уникнути обгортки.
JMM

ОП припинено з лютого 12 року. :( Ось ще +1 для цієї відповіді.
Алмо,

27

Ви можете встановити властивості classNameі idна кореневому елементі: http://documentcloud.github.com/backbone/#View-extend

var ItemView = Backbone.View.extend({
   tagName:  "div",   // I know it's the default...
   className : 'nice',
   id : 'id1',
   render: function() {
     $(this.el).html("Some stuff");
   }       
});

EDIT Включено приклад встановлення ідентифікатора на основі параметрів конструктора

Якщо погляди побудовані, як згадано:

var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});

Тоді значення можна було встановити таким чином:

// ...
className: function(){
    return this.options.item_class;
},
id: function(){
    return this.options.item_id;
}
// ...

3
Я не вважаю цю відповідь правильною, тому що тоді кожен ItemView матиме id: 'id1'. Це має бути розраховано під час виконання на основі model.id.
fguillen 03.03.12

Звичайно, ви можете встановити ідентифікатор як завгодно. Використовуйте функцію, змінну або щось інше. Мій код лише містить приклад, вказуючи, як встановити значення в кореневому елементі.
Йорген

Я додав приклад, що пояснює, як динамічно встановлювати значення на основі параметрів конструктора.
Йорген

Це правильна відповідь. Він використовує функції Backbone правильно для вирішення проблеми.
Марк-Антуан Лем'є

6

Я знаю, що це старе запитання, але додане для довідки. Здається, це легше в нових версіях основної системи. У Backbone 1.1 властивості id та className обчислюються у функції ensureElement(див. З джерела ), використовуючи _.resultзначення підкреслення, якщо classNameабоid є функцією, вона буде викликана, інакше буде використано її значення.

Отже, ви можете вказати className безпосередньо в конструкторі, вказати інший параметр, який буде використовуватися в className тощо ... Багато опцій

так це повинно спрацювати

var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});

var ItemView = Backbone.View.extend({       
  id: function() { return this.model.get('item_id'); },
  className: function() { return this.model.get('item_class'); }
});

Ваш приклад не дійсний, ви б хотілиid: function() { return this.model.get('item_id'); })
Коббі

4

Інші приклади не показують, як насправді отримати дані з моделі. Щоб динамічно додавати ідентифікатор та клас із даних моделі:

var ItemView = Backbone.View.extend({
   tagName:  "div",

   render: function() {
     this.id = this.model.get('item_id');
     this.class = this.model.get('item_class');
     $(this.el).attr('id',this.id).addClass(this.class).html('Some Stuff'); 
   }       
});

Це 'this.className' або 'this.class'?
Gabe Rainbow,

2

Вам потрібно видалити tagName і оголосити el.

'tagName' означає, що ви хочете, щоб магістраль створила елемент. Якщо елемент уже існує в DOM, ви можете вказати el, наприклад:

el: $('#emotions'),

і пізніше:

render: function() { 
     $(this.el).append(this.model.toJSON());
}

2

Спробуйте призначити значення в методі ініціалізації, це буде динамічно призначати id та клас атрибуту div.

var ItemView = Backbone.View.extend( {
    tagName : "div",   
    id      : '',
    class   : '',

    initialize : function( options ) {
        if ( ! _.isUndefined( options ) ) {
            this.id = options.item_id;
            this.class= options.item_class;
        }
    },

    render : function() {
        $( this.el ).html( this.template( "stuff goes here" ) ); 
    }
} );

@Michel Pleasae пішов через цю документацію, backbonejs.org/#View-constructor
Hemanth

0

Ось мінімальний спосіб динамічно змінювати клас елемента подання за допомогою моделі та оновлювати його при зміні моделі.

var VMenuTabItem = Backbone.View.extend({
    tagName: 'li',
    events: {
        'click': 'onClick'
    },
    initialize: function(options) {

        // auto render on change of the class. 
        // Useful if parent view changes this model (e.g. via a collection)
        this.listenTo(this.model, 'change:active', this.render);

    },
    render: function() {

        // toggle a class only if the attribute is set.
        this.$el.toggleClass('active', Boolean(this.model.get('active')));
        this.$el.toggleClass('empty', Boolean(this.model.get('empty')));

        return this;
    },
    onClicked: function(e) {
        if (!this.model.get('empty')) {

            // optional: notify our parents of the click
            this.model.trigger('tab:click', this.model);

            // then update the model, which triggers a render.
            this.model.set({ active: true });
        }
    }
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.