Использование Knockout mapping для сложного JSON - PullRequest
3 голосов
/ 03 апреля 2012

Большая часть нокаута кажется очень интуитивной. Одна вещь, которая для меня странна, это то, как работает подключаемый модуль. Я ожидал / надеюсь, что смогу передать JSON из вызова ajax, и у меня будет своего рода «динамическая» модель представления, доступная для ссылки в моем HTML.

Описание подключаемого модуля даже делает его звучащим так:

"Если ваши структуры данных становятся более сложными (например, они содержат дети или содержат массивы) это становится очень громоздким для обработки вручную. Что позволяет подключаемый модуль сопоставления, так это создание сопоставления. от обычного объекта JavaScript (или структуры JSON) до Наблюдаемый вид модели. "

Но, похоже, вам действительно нужно сначала определить модель представления в своем коде, а затем заполнить ее после факта, используя подключаемый модуль отображения и некоторые данные JSON. Это правильно?

Конкретный пример того, что я пытался сделать.

Я пытаюсь использовать Knockout с Solr (поисковая система, которая возвращает результаты поиска JSON). Структура скелета данных JSON, возвращаемых Solr:

  {
      "responseHeader": {
          "status": 0,
          "QTime": 0,
          "params": {
              "facet": "true",
              "facet.field": "System",
              "q": "testphrase",
              "rows": "1",
              "version": "2.2"
          }
      },
      "response": {
          "numFound": 0,
          "start": 0,
          "maxScore": 0.0,
          "docs": []
      },
      "facet_counts": {
          "facet_queries": {},
          "facet_fields": {
              "System": []
          },
          "facet_dates": {},
          "facet_ranges": {}
      },
      "highlighting": {}
  }

Фактически, это структура, которую я добавляю в свою модель отображаемого вида при первой настройке.

Точно так же вы немного понимаете, как данные JSON возвращаются из Solr: Массив response.docs содержит массив хешей, где хеш-данные состоят из ключей / значений для ваших проиндексированных данных документа. Каждый хэш в массиве - это один документ, возвращаемый в результатах поиска.

Эта часть, кажется, отображается очень хорошо.

«Подсветка» части JSON вызывает у меня проблемы. Когда я пытаюсь ссылаться на поля подсветки в моем HTML, я получаю ReferenceErrors. Вот пример того, как поле подсветки может выглядеть в JSON:

"highlighting": {
    "2-33-200": {
        "Title": ["1992 <b>Toyota</b> Camry 2.2L CV Boots"]
    },
    "2-28-340": {
        "Title": ["2003 <b>Toyota</b> Matrix 2.0L Alignment"]
    },
    "2-31-2042": {
        "Title": ["1988 <b>Toyota</b> Pickup 2.4L Engine"]
    }
}

В моем HTML есть foreach, который пытается проанализировать каждый элемент response.docs, и если подсвечивающая часть объекта содержит совпадения для поля Id этого документа, я хочу заменить выделенный заголовок, а не заголовок по умолчанию , (В приведенном ниже коде «Results» - это имя модели представления, в которую я отображаю JSON.)

<div id="search-results" data-bind="foreach: Results.response.docs">
    <div data-bind="attr: { id: 'sr-' + Id }" class="search-result">
        <h3 class="title"><a data-bind="html: (($root.Results.highlighting[Id]['Title'] != undefined) ? $root.Results.highlighting[Id]['Title'] : Title), attr: {href: Link}"></a></h3>
        <span class="date" data-bind="text: DateCreated"></span>
        <span class="snippet" data-bind="html: Snippet"></span>
    </div>
</div>

Когда я пытаюсь использовать это, я всегда получаю эту ошибку:

Uncaught Error: Unable to parse bindings.
Message: TypeError: Cannot read property 'Title' of undefined;
Bindings value: html: (($root.Results.highlighting[Id]['Title'] != undefined)  ? $root.Results.highlighting[Id]['Title'] : Title), attr: {href: Link}

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

Редактировать Я немного продвинулась. В своем определении отображения я теперь указываю «выделение» следующим образом:

"highlighting": ko.observable({})

Вместо того, чтобы просто установить подсветку на {}. Теперь я, по крайней мере, могу немного взглянуть на подсвечиваемые данные, когда делаю свое отображение. И все же я все еще вижу странные ошибки.

Я упростил свой тестовый HTML-код, чтобы просто выплевывать подсвечивающие данные для каждого результата поиска:

<code><div id="search-results" data-bind="foreach: Results.response.docs">
    <pre data-bind="text: JSON.stringify(ko.toJS($root.Results.highlighting()[Id()]), null, 2)">

Теперь возвращается несколько тегов <pre>, которые выглядят так:

{
  "Title": [
    "1992 <b>Toyota</b> Camry 2.2L CV Boots"
  ]
}

Однако, если я изменю этот HTML-код на этот:

<code><pre data-bind="text: $root.Results.highlighting()[Id()]['Title']">

Я продолжаю получать такие ошибки:

Message: TypeError: Cannot read property 'Title' of undefined;
Bindings value: text: $root.Results.highlighting()[Id()]['Title']

Не имеет смысла для меня! Мой предыдущий тест показал, что доступные данные содержат клавишу «Заголовок», почему я не могу получить доступ к этим данным?

Редактировать Я создал jsfiddle , но, конечно ... он работает как положено. Я не могу воспроизвести мою проблему на jsfiddle. : - (

Редактировать ОК. Я добиваюсь некоторого прогресса здесь, но все еще очень озадачен тем, что происходит. Сначала я изменил свой HTML-код для отладки так:

<code><div id="search-results" data-bind="foreach: Results.response.docs">
    <pre data-bind="text: console.log($root.Results.highlighting()[Id()])">

Затем я отправил свой вызов ajax и заметил в консоли Chrome этот вывод:

undefined
undefined
> Object

По какой-то причине цикл foreach зацикливается на 3 файлах Results.response.docs, и первые два не сопоставляются ни с чем в моем объектеlights (), поэтому они возвращают неопределенное значение, и именно поэтому мой попытка получить свойство .Title не удалась.

Чтобы подтвердить это, я обернул ko if: $root.Results.highlighting()[Id()] вокруг этого блока и, наконец, смог получить доступ к свойству .Title во время цикла foreach без ошибки JS.

Это все еще оставляет меня с вопросом о том, почему / как есть 3 объекта Results.response.docs, которые зацикливаются. Возможно, привязка foreach запускается 3 раза, и первые 2 раза подсвечивающий объект пуст, а в третий раз он наконец заполняется? Но мне трудно понять, почему это так.

Еще одна возможная подсказка: если я вызову ajax-вызов второй раз, не перезагружая страницу, я вижу, что все эти 3 «прохода» возвращают действительный объект каждый раз в журнале консоли. Таким образом, вместо двух undefined и объекта, это три объекта подряд.

В моем выводе HTML я вижу только одну строку данных. Кажется, это доказывает, что он не зацикливается на 3 элементах, а фактически запускается 3 раза. Вопрос остается ... ПОЧЕМУ?

1 Ответ

3 голосов
/ 03 апреля 2012

Подключаемый модуль работает так, как вы ожидаете. Ваша проблема просто в том, что вы ожидаете, что плагин создаст наблюдаемые на каждом уровне объекта. Это не так, как работает плагин. Он будет создавать только наблюдаемые свойства «листа». Так что в вашем случае $root.Results.highlighting не создается как наблюдаемое. Свойства идентификатора на документах, однако, создаются как наблюдаемые, так что решение:

$root.Results.highlighting[Id()]

Я полагаю, что вы, возможно, были сбиты с толку, потому что одна из ваших скрипок присваивала self. Дважды результаты, которые заставляли его работать в одном направлении, когда на самом деле проблема маскировалась.

Вот рабочая версия

http://jsfiddle.net/madcapnmckay/UaBKe/

Надеюсь, это поможет.

...