2014-08-12 3 views
5

Я пытаюсь изучить Handlebars.js и подумал о том, как использовать его на сайте im im. Это сайт на одной странице, в котором будут два контейнера с тремя div в каждом, который будет содержать встроенных игроков Soundcloud через их API.Исключить HTML из тега скрипта

При включении div, которые содержат запросы API в теге скрипта, обработанные Handlebars, сайт ведет себя очень ненадежно и отображает только некоторых из шести игроков. Это не совсем непротиворечиво, но может показывать разных игроков все время. Проблема, кажется, в Soundcloud javascript SDK, но я не чувствую, что знакомы, чтобы копаться там слишком много.

Поэтому я подумал о том, чтобы исключить игровые divs (см. Код), чтобы они мгновенно загружались и не обрабатывались как javascript, но все же отображались под заголовком исполнителя в заголовке-заполнителе (который установлен чтобы содержать результат скрипта Handlebar).

Проблема в том, что я не могу придумать хороший способ сделать это, есть ли какая-нибудь простая функция (с помощниками Handlebars), которая поможет мне сделать то, что я хочу?

<div id="placeholder"></div> 
<script id="player-template" type="text/x-handlebars-template"> 
      <div id="container1"> 
        Artist1 - {{title1}} 
        <div id="player1"></div> 
        Artist2 - {{title2}} 
        <div id="player2"></div> 
        Artist3 - {{title3}} 
        <div id="player3"></div> 
      </div> 
      <div id="container2"> 
        Artist4 - {{title4}} 
        <div id="player4"></div> 
        Artist5 - {{title5}} 
        <div id="player5"></div> 
        Artist6 - {{title6}} 
        <div id="player6"></div> 
      </div> 
    </script> 
    <script src="js/handlebars_title_script.js"></script> 

Одно решение, конечно, чтобы сделать один шаблон Handlebar для каждого артиста - Название DIV и установить заполнитель каждого шаблона в DIV, содержащего только Artist1 - {{title1}}, но это действительно разрушает точку использования Ручки для минимизации моего кодирования HTML.

Кто-нибудь получил подсказку для меня, как это решить?

Edit 1:

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

$(document).ready(function() { 
    var hey = "heya"; 
    SC.get("https://stackoverflow.com/users/artist/tracks", {limit: 1}, function(tracks){ 
    var title_data1 = tracks[0].title; 
    hey = tracks[0].title; 
    alert(title_data1); 
    alert(hey) 
    }); 


//Data that will replace the handlebars expressions in our template 
var playerData = { 
    title1 : hey, 
}; 

document.getElementById('player-placeholder').innerHTML = playerTemplate(playerData); 

}); 

Извините за плохой настрой. Единственная проблема с этим кодом заключается в том, что title1 (в переменной playerData, которая является контекстом Handlebars) получает первое значение переменной hey («heya»). Когда он будет предупрежден о всплытии реального названия, как я могу заставить title1 использовать это значение вместо того, чтобы вставлять эту переменную в более javascript (так как это приводит к тому, что упомянутая выше ошибка возникает, когда игроки появляются странно)?

ответ

2

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

После взятия вашего примера JsFiddle я смог заставить его работать так, как я думаю, вы хотели.

Working Demo

HTML:

<body> 
    <div id="wrapper"> 
     <div id="player-placeholder"><!-- rendered template goes here --></div> 

     <!-- handlebars template: --> 
     <script id="player-template" type="text/x-handlebars-template"> 
      {{#each tracks}} 
       <div class="track"> 
        <header class="header"> 
         <span class="artist">{{user.username}}</span> - <span class="title">{{title}}</span> 
        </header> 
        <section class="player" data-uri="{{permalink_url}}"> 
        </section> 
       </div> 
      {{/each}} 
     </script> 
    </div> 
</body> 

JavaScript:

$(document).ready(function() { 

    /* 
    get your template string See: 

    http://api.jquery.com/id-selector/ 
    http://api.jquery.com/html/ 
    */ 
    var source = $('#player-template').html(); 

    // compile the template into a handlebars function 
    var template = Handlebars.compile(source); 

    // initialize sound cloud api 
    SC.initialize({ 
    client_id: '90fb9e15c1e26f39b63f57015ab8da0d' 
    }); 

    /* 
    This function will be called once the HTTP transaction 
    started by SC.get(...) completes. Note, there's nothing 
    wrong with doing this as an anonymous function, I'm 
    simply assigning it to a variable to show that this 
    is a distinct function that's called later 
    */ 
    var callback = function(tracksResponse){ 
    /* 
     once a response has been received, we'll use the response 
     to generate a new context to pass to the template function. 
     Note, you can use the template function in here because its 
     within a closure. See: 
     https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures 
    */ 
    var context = { tracks: tracksResponse }; 
    var html = template(context); 

    /* 
     assign the rendered html to your placeholder on the page 
     see: http://api.jquery.com/html/ 
    */ 
    $('#player-placeholder').html(html); 

    /* 
     Now that the html is rendered and on the page, its time to 
     setup the sound cloud players. Note the css classes I assigned 
     to the track/player. This line selects all of the player's and 
     runs the function over each. See: 

     http://api.jquery.com/class-selector/ 
     http://api.jquery.com/each/ 
    */ 
    $('.track .player').each(function(index, e){ 
     var $this = $(this); // jQuery reference to the current object in 'each loop' 

     /* 
     I assigned the permalink_url of each track to an attribute called 'data-uri' 
     This line gets the value of that attribute. See: 

     http://api.jquery.com/data/#data2 
     */ 
     var permalink = $this.data('uri'); 
     var urlParameters = '/&maxheight=100&maxwidth=300&format=json&sharing=false'; 

     /* 
     finally we call the sound cloud oEmbed function feeding it the url 
     stored in the element, as well as the actual element. 

     (see the second argument of the each function: http://api.jquery.com/each/) 
     */ 
     SC.oEmbed(permalink + urlParameters, e); 
    }); 
    }; 

    // get tracks for your artist 
    // Note the "limit" in the object controls the number of items returned 
    // by sound cloud 
    SC.get("https://stackoverflow.com/users/theshins/tracks", {limit: 5}, callback); 
}); 

Что пошло не так?

JavaScript - это однопоточный, асинхронный, управляемый событиями язык.Этот гигантский аппетит означает, что у JavaScript действительно нет понятия потоки (я намеренно игнорирую WebWorkers). Чтобы обойти это ограничение, почти все IO в JavaScript не блокируются (асинхронны).

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

  • Создать функцию обратного вызова
  • операции
  • вызовы IO, передавая ему аргументы, он требует, чтобы завершить, а также обратный вызов
  • Execution возвращает немедленно
  • когда-нибудь в будущем, функция обратного вызова вызывается

в оригинальном примере $(document).ready(function() { ... }) очередей анонимную функцию, чтобы стрелять, когда делать Событие cument.onReady поднято. Однако в вашем исходном примере было назначено два вызова. Это не проблема, фактически .ready(...) предназначен для приема и обработки многих обратных вызовов. Однако, когда вы поступили не так, у вас было два отдельных блока кода, которые назывались SC.get(...).

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

Как это было установлено

Чтобы устранить проблему синхронизации вам необходимо синхронизировать, когда вы получаете вашу информацию, когда вы строите свой шаблон HTML, и при инициализации элементов управления. Существует много способов сделать это, и многие фреймворки поддерживают идею promises, чтобы помочь получить контроль над порядком, в котором запущены асинхронные события, и вызваны их обратные вызовы.

Я взял простой маршрут и объединил все ваши звонки SC.get в один, а затем в его обратный вызов. Я обрабатываю шаблон руля и инициализирую игроков SoundCloud.

+0

Спасибо за помощь. Мне сложно понять это, хотя (новичок, я знаю), но это помогло мне подумать об альтернативном решении. Пожалуйста, проверьте мои изменения, если у вас есть время! – user3880485

+1

Это хорошо, для меня это похоже на то, что вы столкнулись с тем, как работает JavaScript с асинхронным режимом работы с событиями. Это может быть довольно ловушкой при изучении языка. Я добавил еще один раздел ответа. – klyd

+0

Еще раз спасибо. Хм, хорошо, я это проверю. На самом деле ваш код здесь почти идентичен моему js-коду, прежде чем я внес изменения. И хотя этот код генерирует правильные данные Handlebar в нужном месте в HTML, дело в том, чтобы переносить данные переменных в другую функцию, которая заставляет игроков казаться странными. Вы можете увидеть какой-либо другой способ объявления треков [0] .title для переменной, которая может быть прочитана в нужный момент в переменных данных? – user3880485

Смежные вопросы