с jsRender, как вы извлекаете определенный элемент из массива, используя что-то другое, кроме порядкового номера?

Я пытаюсь отобразить некоторые данные JSON с помощью jsRender. Ниже приведен пример данных JSON.

"PageContentList": [
    {
        "ContentId": 51, 
        "Title": "60 seconds with Rick", 
        "ContentMediaTypeList": [
            {
                "MimeType": "image/png", 
                "MediaTypeName": "Image", 
                "Path": "http://local.admin.solutiaconsulting.com/uploads/4a906d8e-983a-4b54-a627-0e8d48145620.png"
            }, 
            {
                "MimeType": "video/webm", 
                "MediaTypeName": "Video", 
                "Path": "http://local.admin.solutiaconsulting.com/uploads/3a6c56c3-0ef9-4f57-9c84-9caa48a09044.webm"
            }
        ]
    }
]

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

{{:ContentMediaTypeList[1].Path}}

и я знаю, что могу сделать это:

{{для ContentMediaTypeList}} {{if MediaTypeName == 'Video'}} {{:Path}} {{/if}} {{/for}}

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


person Tom Schreck    schedule 01.08.2012    source источник
comment
Вы можете использовать вспомогательные функции для обработки ваших данных (пройтись по списку и вернуть тот, у которого указан целевой тип носителя), а затем выполнить {{:~mediaType('Image').Path}}. Вы даже можете определить собственный тег и сделать: {{mediaType 'Image'}}{{:Path}}{{/mediaType}}. Взгляните на примеры, и вы найдете примеры этих методов.   -  person BorisMoore    schedule 03.08.2012
comment
Это хороший ответ, потому что это именно то, о чем он просил в первую очередь. Но я думаю, что решение, которое Том придумал сам, даже лучше. Использование этих вспомогательных функций добавило бы в представление больше логики, а также сделало бы его более абстрактным, поскольку реальная логика скрыта в помощнике. Превратить его в два разных массива очень просто.   -  person Charlie Rudenstål    schedule 03.08.2012


Ответы (2)


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

Единственное исключение, о котором я могу подумать в этом случае, - это если вы хотите ограничить количество отображаемых элементов. Это может быть или не быть подходящей задачей для представления в зависимости от ситуации.

Примеры:

Держите логику ограничения вне поля зрения:
– Список вопросов о переполнении стека с пейджингом (лимит, смещение, сортировка)

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

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

Вот простой способ отфильтровать ваши данные с помощью underscore.js.

 var videoContent = _.filter(contentMediaTypeList, function(mediaType) {
      return mediaType.mediaTypeName == "video"; 
 });

Рабочий JSFiddle: http://jsfiddle.net/n98yW/

Или создайте из него closure для повторного использования

var mediaTypeFilter = function(mediaTypeName) {
     return function(contentMediaTypeList) {
           return _.filter(contentMediaTypeList, function(currMediaType) {
                return currMediaType.MediaTypeName == mediaTypeName;
           });
     }
};

И использовать это так

var videoFilter = mediaTypeFilter("video");    
var videoContent = videoFilter(contentMediaTypeList);

Вот еще JSFiddle для этого решения с использованием замыкания: http://jsfiddle.net/GA55g/2/

person Charlie Rudenstål    schedule 01.08.2012
comment
Спасибо за ваш вклад. Я думаю, что представление должно иметь возможность извлекать данные из предоставленных ему данных, чтобы генерировать желаемый результат. Я не применяю никаких бизнес-правил к данным в представлении. Я просто пытаюсь извлечь данные из данных, отправленных в представление. Разве это не уместно? - person Tom Schreck; 02.08.2012
comment
Это зависит от вашего представления об уровнях приложения и о том, как они должны взаимодействовать. Если вы действительно хотите использовать для этого язык шаблонов в JSRender, то я думаю, что цикл for, который вы использовали в своем вопросе, - единственный путь. - person Charlie Rudenstål; 02.08.2012

Спасибо, Чарли, за ответ. В итоге я изменил структуру своего JSON на это:

"PageContentList": [
    {
        "ContentId": 44, 
        "Title": "Company Name", 
        "Gallery": {
            "Images": [
                {
                    "Path": "http://local.admin.solutiaconsulting.com/uploads/9b577ef7-ea8a-42a1-b967-89debbc634c0.jpg", 
                    "MimeType": "image/jpeg", 
                    "ImageWidth": 0, 
                    "ImageHeight": 0, 
                    "AltText": null
                }
            ], 
            "Videos": [ ]
        }
    },
   .... 
]

Затем для моего шаблона:

{{for PageContentList}}
<video id="whatIsSolutiaVideo" class="video-js vjs-default-skin" controls width="{{:Gallery.Images[0].ImageWidth}}" height="{{:Gallery.Images[0].ImageHeight}}" poster={{:Gallery.Images[0].Path}}" preload="auto">
{{for Gallery.Videos}}
<source type="{{:MimeType}}" src="{{:Path}}">
 {{/for}}
 </video>
 {{/for}}

Я знаю, что каждые данные JSON будут иметь раздел для изображений, видео и т. д. Теперь это становится проблемой ввода данных. Если человек, вводящий данные, сделал свою работу правильно, тогда данные будут. Подход, к которому я перешел, обеспечивает правильную структуру данных. Спасибо, что заставил меня обдумать это.

person Tom Schreck    schedule 02.08.2012
comment
+1 Разделение видео и изображений на два разных массива делает ваш код менее сложным, и это всегда хорошо. Отличное решение. - person Charlie Rudenstål; 03.08.2012