Nano Hash - криптовалюты, майнинг, программирование

Визуализация рекурсивной структуры с использованием CompositeView при инкапсуляции каждой модели в ItemView с помощью Marionette

Я начну с четкого вопроса и объясню после:
Как правильно инкапсулировать модель, содержащуюся в CompositeView, в ItemView.

Моя проблема проста, но я не могу заставить что-то хорошее работать. У меня есть дерево заметок. Каждая заметка является Backbone.model и имеет коллекцию @descendants, затем у меня есть Backbone.Collection для представления этого дерева (экземпляром которого является @descendants). Я устанавливаю базовую CollectionView с CompositeView в качестве itemView. Все отрисовывалось отлично, чему я был очень рад. Это рабочее решение показано в первом фрагменте кода!

Вот в чем проблема. Опираясь на это, я столкнулся с этой проблемой: События, инициированные для всей иерархии, что имеет смысл для того, как мои события были привязаны. Сначала я просто добавлял уникальные селекторы (добавлял data-guid к своим html-элементам, чтобы я мог получить их по нему), и это работало нормально, хотя это уже становилось хакерским. Но возникла другая похожая проблема, поэтому я решил, что мне нужно решение для этого. Итак, сказал я себе, давайте инкапсулируем каждую модель в ItemView и используем составное представление для их рекурсивного рендеринга. Но... Это было не к лучшему во всех мирах...

Вот что у меня было в начале:

class Note.ModelView extends Marionette.CompositeView
  template: "note/noteModel"
  id: "note-item"
  itemViewContainer: ".note-descendants"
  ui:
    noteContent: ".noteContent"
  events:
    "keypress .noteContent": "createNote"
    "click .destroy": "deleteNote"
  # ...
  initialize: ->
    @collection = @model.descendants
  # ...

class Note.CollectionView extends Marionette.CollectionView
  id: "note-list"
  itemView: Note.ModelView
  initialize: ->
    @listenTo @collection, "sort", @render

Теперь я перенес все, что относится к рендерингу Модели, в новый ItemView.

  class Note.ModelView extends Marionette.ItemView
    template: "note/noteModel"

    ui:
      noteContent: ".noteContent"
    events: ->
      guid = @model.get 'guid'
      events = {}
      events["keypress #noteContent#{guid}"] = "createNote"
      events["blur #noteContent#{guid}"] = "updateNote"
      events["click #destroy#{guid}"] = @triggerEvent 'deleteNote'

    initialize: ->
      @bindKeyboardShortcuts()
      @listenTo @model, "change:created_at", @setCursor

  class Note.TreeView extends Marionette.CompositeView
    template: "note/parentNote"
    itemView: Note.ModelView

    initialize: ->
      @collection = @model.descendants
      @listenTo @collection, "sort", @render
      _.bindAll @, "renderItem"
    renderItem: (model) ->
      if model.get('parent_id') is 'root'
        itemView = new Note.ModelView model: model
        itemView.render()
        @$el.append itemView.el
    onRender: ->
      @collection.each this.renderItem
      @renderItem @model
    appendHtml: (collectionView, itemView) ->
      @model.descendants.each (note) =>
        iv = new Note.ModelView model: note
        iv.render()
        @.$('.note-descendants').append iv.el


  class Note.CollectionView extends Marionette.CollectionView
    id: "note-list"
    itemView: Note.TreeView
    initialize: ->
      @listenTo @collection, "sort", @render

и шаблон noteMode (parentNote сейчас просто пустой шаблон)

<button class="btn btn-danger btn-xs untab">UN</button>
<button class="btn btn-success btn-xs tab">TAB</button>
<div class="noteContent">{{{indent}}}{{{title}}}</div>
<button class="destroy"></button>
<div class="note-descendants"></div> # That is where I'm putting the children notes

Так что это почти работает. Но это хаки и ... ну, это все еще не совсем работает. Я прочитал всю документацию, и я прочитал эти две ссылки Дерик Бейли о вложенной структуре и CompositeView и Дэвид Сульк о вложенных представлениях, но я все еще чувствую, что упускаю некоторые важные детали.

В качестве ответа я ищу любой намек или любой общий способ справиться с этим с помощью Marionette. Я действительно ищу что-то чистое, так как это будет одна из угловых частей, на которых будет построено приложение.
Может быть, я ищу не в том месте? Все будет приветствоваться!! Большое Вам спасибо

Я желаю вам всем очень приятной ночи. Спасибо за уделенное время.



Ответы:


1

Я собираюсь объяснить вам, другими словами, то, что Дерик Бейли уже заявил в блоге, на который вы ссылались.

Просмотры

Вам нужно два представления, чтобы сделать эту работу.

Первое, «материнское представление», является самым внешним представлением, которое содержит рекурсивную структуру в качестве своих дочерних узлов. Это может быть либо Marionette.CollectionView, либо Marionette.CompositeView.

Второе представление — это ваше рекурсивное представление, то есть оно должно быть Marionette.CompositeView. Вы делаете Marionette.CompositeView рекурсивным, НЕ указывая свойство "itemView". При отсутствии свойства itemView Marionette.CompositeView будет использовать СЕБЯ для отображения моделей коллекции, которую ему дали.

Подборка

Вам нужна коллекция, которая является либо Backbone.Collection вложенных Backbone.Collections, либо просто Backbone.Collection, которая содержит глубоко вложенный хэш. В последнем случае вам не нужно забывать преобразовывать простые хэши в Backbone.Collections при передаче их в Marionette.CompositeView (как это делается ниже в методе initialize() RecursiveView).

Собираем все вместе

var RecursiveView = Marionette.CompositeView.extend({
    template: '#someTemplate',
    initialize: function () {
        this.collection = this.model.get('children')
    }
});

var MotherView = Marionette.CollectionView.extend({
    itemView: RecursiveView,
    collection: new Backbone.Collection([{key: 'value', children: [{}, {}, {}]}])
});

Проблема: Всплывающие события

Естественно, события DOM теперь будут всплывать, поэтому этот код

var RecursiveView = Marionette.CompositeView.extend({
    events: {
        'click button': someCallback
    }
});

будет охватывать все события представления, на которое оно ссылается, а также всех его потомков.

Самым простым решением этой проблемы является использование прямого потомка css selectr >, например.

var RecursiveView = Marionette.CompositeView.extend({
    events: {
        'click >button': someCallback
    }
});

Если этого недостаточно, одним из эффективных решений будет предотвращение автоматического всплытия событий, например.

var RecursiveView = Marionette.CompositeView.extend({
    events: {
        'click button': function (event) {
            event.stopPropagation();
            // or event.stopImmediatePropagation() depending on your use case
            // cf. http://stackoverflow.com/a/5299841/899586 and 
        }
    }
});
08.10.2013
  • В чем разница между этим кодом и первым, что я опубликовал? Нет... У меня это работает, большое спасибо. Я ищу способ инкапсулировать созданный html, чтобы самое внутреннее представление имело доступ только к своему html, а не ко всей иерархии html. 08.10.2013
  • ладно, извините, неправильно прочитал ваш пост, честная ошибка. почему бы вам не добавить селектор прямого потомка >, чтобы проверять только события DOM, происходящие с прямыми потомками? Если вам этого недостаточно, я бы предпочел решить проблему на стороне распространения событий: остановить всплытие событий в вашем рекурсивном представлении. 09.10.2013
  • Итак, во-первых, спасибо, что нашли время ответить! Так что решения, которые вы предлагаете, действительно работают, это именно то, что у меня есть на данный момент. Проблема действительно в том, что я нахожу это хакерским, и я хотел чисто инкапсулировать все в ItemView. Но, играя с кодом, я пришел к выводу, что это может быть невозможно, потому что при этом вы явно теряете рекурсивность. А потом вы просто переделываете его. У вас есть какой-нибудь намек в этом направлении? Если больше ничего не появится, я отмечу ваш ответ, хотя на самом деле он мне не помог, вы потратили время! 09.10.2013
  • Проблема в том, что всплытие событий происходит НЕ в области backbone.view/marionette.view, а исключительно внутри самой DOM. На стороне магистрали/марионетки не происходит диспетчеризация событий, которую вы могли бы отключить. Всплывающие события здесь — чисто «особенность» DOM. Следовательно, вам придется построить плоскую иерархию в DOM, потому что события всплывают только к своим родителям, а не к своим братьям и сестрам. Затем вам понадобится соответствующий код CSS или JS, чтобы создать оптическую иллюзию того, что рассматриваемые элементы DOM на самом деле находятся в визуальной иерархии... :) 10.10.2013
  • Таким образом, event.stopPropagation() является «хаком», позволяющим прервать стандартную функцию DOM. Это действительно может считаться хакерским, поскольку в других местах вашего кода вы можете ожидать, что событие всплывет. Поэтому первое решение с прямыми селекторами потомков обычно предпочтительнее. Но я думаю, что есть преступления похуже, чем следующее решение (2). 10.10.2013
  • Да, но представление инкапсулирует элементы DOM. Таким образом, вы выбираете не весь DOM, а только views.el. Вот почему я хотел попробовать это решение. Селекторы прямых потомков выполняют свою работу, но, как показано в первой ссылке, которую я разместил в своем вопросе, Дерик Бейли решает эту проблему с помощью ItemView, инкапсулирующего все (на самом деле, это только базовое представление, но оно эмулирует поведение ItemView) . Вот что побудило меня попытаться реорганизовать CompositeView! Кроме того, у меня есть сочетание клавиш, для которого требуется e.stopPropagation(), и я не знаю, может ли это быть долгосрочным решением. 10.10.2013
  • Я новичок в Backbone.Marionette, а не в Javascript. В моем последнем проекте использовался Angular, и это упростило рефакторинг кода в директивах для сильно инкапсулированных и многократно используемых компонентов. Я как бы пытаюсь правильно прочувствовать Марионетту. Я думаю, мне придется придерживаться этого на данный момент. Спасибо @JohnSpartan. 10.10.2013
  • Вам действительно не нужны два представления для древовидной структуры. Достаточно одного рекурсивного составного представления. Материнское представление будет просто его корневым экземпляром. 09.12.2013
  • @DmitriZaitsev вы делаете, если вам нужен внешний контейнер для переноса вложенных представлений. 24.07.2014
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..