Simple iTunes search using basis.js

Search by filters via server. Also example demonstrates how build your own component classes. Framework's components are not using.

by ishaba

HTML

<script src="http://yourjavascript.com/24215954185/basisjs-1-2-5-dev.js"></script>
<script type="text/basis-template" id="toolbar">
  <div class="toolbar">
    <!--{searchField}--> <!--{countryField}--> <!--{typeField}-->
  </div>
</script>

<script type="text/basis-template" id="field-text">
  <input value="{value}" placeholder="Search..." event-keyup="updateValue" event-change="updateValue"/>
</script>

<script type="text/basis-template" id="field-select">
  <select value="{value}" event-change="updateValue"/>
</script>

<script type="text/basis-template" id="field-select-item">
  <option value="{value}">{caption}</option>
</script>
      
<script type="text/basis-template" id="entry-list">
  <div>
    <!--{toolbar}-->
    <!--{childNodesHere}-->
    <div class="entry-list__loading entry-list__loading_{childNodesState}">loading...</div>
    <div class="entry-list__empty entry-list__empty_{childNodesState} entry-list__empty_{empty}">Nothing found</div>
  </div>
</script>
      
<script type="text/basis-template" id="entry">
  <div class="entry">
    <img class="entry__image" src="{thumbnail}" height="100"/>
    <span class="entry__description">
      <span class="entry__name">{name}</span>
      <span class="entry__price">{price} {currency}</span>
    </span>
  </div>
</script>

CSS

.entry-list__loading,
.entry-list__empty
{
  display: none;
}
.entry-list__loading_processing,
.entry-list__empty_empty.entry-list__empty_ready
{
  display: block;
}

.entry
{
  padding: 5px;
  border-bottom: 1px solid #DDD;
  overflow: hidden;
}
.entry:hover
{
  background: #F0F0F0;
}
.entry IMG
{
  float: left;
  margin-right: 15px;
}
.entry__description
{
  overflow: hidden;
}
.entry__name
{
  display: block;
  font-size: 25px;
}
.entry__price
{
  font-size: 35px;
  color: #AA9988;
}

JavaScript

basis.require('basis.entity');
basis.require('basis.net.service');
basis.require('basis.net.jsonp');
basis.require('basis.ui');

// Сервис для работы с iTunes
var iTunesService = new basis.net.service.Service({
  transportClass: basis.net.jsonp.Transport // работаем по JSONP
  // тут могут быть общие настройки для все транспортов/запросов
});

//
// Тип сущность iTunes
//
var ITunesEntry = basis.entity.createType('ITunesEntry', {
  trackName: String,
  artworkUrl100: String,
  trackPrice: Number,
  releaseDate: String,
  country: String,
  currency: String
});

//
// Функция для получения набора с результами
// используется кеш
//
ITunesEntry.byFilters = (function(){
  var keys = ['entity', 'media', 'country', 'term'];
  var cache = {};

  // класс для создания наборов с результатами
  var SearchResults = basis.data.Dataset.subclass({
    syncAction: iTunesService.createAction({
      request: function(){
        return {
          url: 'https://itunes.apple.com/search?limit=100&' + this.params
        };
      },
      success: function(data){
        this.set(data.results.map(ITunesEntry.reader).map(ITunesEntry));
      }
    })
  });

  // генерация строки с параметрами по переданному объекту
  function getParams(data){
    var params = [];

    for (var i = 0, key; key = keys[i]; i++)
    {
      var value = data[key];

      if (typeof value == 'string')
        value = value.trim();

      if (value != null && value !== '')
        params.push(key + '=' + value);
    }

    return params.join('&');
  }

  return function(filters){
    if (!filters || !filters.term)
      return null;

    var params = getParams(filters);

    if (params in cache == false)
      // если набора с переданными параметрами еще нет, создаем его
      // и добавляем в кеш
      cache[params] = new SearchResults({
        filters: filters,
        params: params
      });

    return cache[params];
  };
})();

//
// Создаем классы полей (по сути компоненты)
//

// абстрактное поле,...