Exclude HTML from script tag

I am trying to learn Handlebars.js and thought about how to use it on the im site. This is a one-page site that will have two containers with three divs in each, which will contain Soundcloud built-in players through their API.

When you enable divs that contain API requests in a script tag processed by Handlebars, the site behaves very unreliable and displays only some of the six players. He is not very consistent, but can show different players all the time. The problem seems to be in the Soundcloud javascript SDK, but I don’t feel familiar to dig too much there.

Therefore, I thought about somehow excluding game divs (see code) so that they instantly load and not be processed as javascript, but still appear under the name artist in the placeholder (which is set to contain the result of the Handlebar script) .

The problem is that I cannot come up with a good way to do this, is there any simple function (possibly with Handlebars helpers) that will help me do what I want?

<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> 

One solution, of course, is to make one Handlebar template for each Artist - Title div and set the placeholder of each template to a div containing only Artist1 - {{title1}}, but this really breaks down the point of using Handlebars to reduce to minimize my html code.

Has anyone got a clue for me how to solve this?

Change 1:

I found another solution by changing my javascript (which I did not publish at first, so obviously you could not help me).

 $(document).ready(function() { var hey = "heya"; SC.get("/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 ); }); 

Sorry for the bad mood. The only problem with this code is that title1 (in the playerData variable, which is the Handlebars context) gets the first value of the hey ("heya") variable. When he warns that a real title pops up, how can I get title1 to use this value instead of inserting the variable into more javascript (as this leads to the fact that the previously mentioned error involving the players seemed strange)?

+5
source share
1 answer

Note: in all comments, this answer has changed dramatically. Please view earlier versions if you want to see the evolution of this answer.

After receiving the JsFiddle example, I was able to make it work as you think.

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 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 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 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("/users/theshins/tracks", {limit: 5}, callback); }); 

Something went wrong?

JavaScript is a single-threaded, asynchronous, event-driven language. This gigantic appetite means that JavaScript really has no concept of threads (I intentionally ignore WebWorkers). To get around this limitation, almost all JavaScript IOs are non-blocking (asynchronous).

Whenever an asynchronous I / O transaction begins, it immediately returns to the caller, and code execution continues. Almost all I / O transactions accept a β€œcallback” or have an event that will be raised when the I / O transaction completes. This means that the basic pattern for all I / O follows something like this:

  • Create callback function
  • Call an I / O operation by passing it the arguments it needs, plus a callback
  • Execution returns immediately
  • Sometime in the future, the callback function is called

In your original example, the $(document).ready(function() { ... }) queue calls an anonymous function when the document.onReady event fires. However, in your original example, two calls were assigned. This is not a problem, in fact .ready(...) designed to accept and queue many callbacks. However, when you did wrong, you have two separate blocks of code called SC.get(...) .

Technically, if this is done correctly, this will not be a problem, but your first in the finished callback was instructed to customize the HTML pages, while your second callback tried to initialize the html-based player controls on the page. Remember that these events and I / O are asynchronous; they fire in any order. Essentially, it became a time issue, you tried to initialize the controls on the page and generate HTML code to display on the page at the same time.

How was fixed

To fix the synchronization problem, you need to synchronize when you receive information, when you build the HTML template and when you initialize your controls. There are many ways to do this, and many frameworks support the idea of promises in order to gain control over the order in which asynchronous events are triggered and the calls being called.

I took a simple route and combined all of your SC.get calls into one, and then in its callback I process the handlebars template and initialize the SoundCloud players.

+2
source

Source: https://habr.com/ru/post/1200140/


All Articles