How I do use the loading_indicator.png provided in the design resources folder to make it act like an ajax loader?
This is how I display a loading indicator when starting my app, taken from the 'home' application (What's New). In your index.html:
<div class="loading">
<div class="throbber"><div></div></div>
</div>
In you app.css:
#import url("sp://import/css/eve.css");
adam.css being the dark Spotify theme and eve.css the light. Then, when your application is finished loading, just remove the element. You can do it with the dom methods in the spotify dom.js. In your app.js:
var dom = sp.require('sp://import/scripts/dom');
var loadingEl = dom.queryOne('.loading');
dom.destroy(loadingEl);
I don't know if the dom.js will be in the official API or not. Otherwise you can remove it any other way (standard dom methods, other js libraries you're using, etc):
var loadingEl = document.querySelector('.loading');
loadingEl.parentNode.removeChild(loadingEl);
Note that the above example does not necessarily use the loading_indicator.png but whatever images that are used by the adam.css and eve.css themes.
If you wan't to use the loader as a normal ajax loading indicator inside your app, then all the normal rules of web apps apply. Display loader when initiating ajax call, hide it in completed-callback, position it with css.
I realize this is an old topic, but with the 1.X API there is an easier way to do this by using the Throbber class which allows you to instantiate and hide fairly simply via JS.
var tracks = document.getElementById('tracks');
var throbber = Throbber.forElement(tracks);
// (wait for tracks to load and render)
throbber.hide();
Just make sure to include the Throbber class at the beginning of your JS:
require([
'$views/throbber#Throbber'
], function (Throbber) {
Related
I'm writing an extension that scrapes web pages using jquery. After a while I start getting net errors saying resources not available and errors in the console loading images in the pages I'm scraping. I thought it might be $.get() loading it as html somehow, but it still happens when I use a raw XMLHttpRequest and it appears even when I call $(text) with static text.
Looking in the application tab of my background page I can see that there are images, even though they don't exist in the html. For example run this in the console of any extension background page:
$('<div>Hello, world!<img src="https://www.gravatar.com/avatar/fdc806d0a8834e57b2d9309849dea8cd"/></div>')
And you can see the image was loaded on the Application tab in dev tools, though it isn't in the html of the page when inspected and but it's visible on the network tab:
I assume that jquery is creating dom elements to use the browser's capabilities for finding elements, and that chrome is happily pre-fetching that image even though the element isn't on the page and the page will never be visible anyway, but it is causing me errors besides the extra network traffic.
I've tried disabling 'precache' in chrome://flags but that didn't work. For now I'm replacing <img with <noimg which seems to work but is not ideal:
$(text.replace(/<img /g, '<noimg '))
Is there a way to keep this from happening? Is there another library besides jQuery (like cheerio in node) that wouldn't actually create dom objects?
Use the built-in DOMParser to parse the HTML into a detached document, then use jQuery on that document object:
var doc = new DOMParser().parseFromString(yourHTMLstring, 'text/html');
$('.some.selector', doc).attr('foo', 'bar');
In case there may be relative links in the HTML, add a base element explicitly:
$(doc.head).append('<base href="' + realFullURL + '">')
I'm trying to learn the jade template system and backbone.js in the context of a (relatively simple) node.js webapp. I'm using express.js as my framework. Anyway, backbone.js looks really interesting and powerful, but I don't want to render my clients on the client side.
I'd rather render server-side with node and jade, send the client the rendered page, and just modify live content using backbone. What's the best way to go about this? In other words, what's the best way to use backbone with a page that's already rendered and structured? I realize that I'm not leveraging backbone to it's full power, but I'm pretty much just trying to use backbone rather than a bunch of jQuery selectors and event handlers.
Your backbone view can reference an existing DOM element by passing a reference to the element as el when instantiating the view.
var myViewInstance = new MyViewClass({el: $('#existingDOMElement')});
Any event handlers you have declared in your view class will be bound to any child elements matching the event selectors. Ex:
<html>
<body>
<div id='myView'>
<a class='foo'>Foo</a>
</div>
<script>
var MyViewClass = Backbone.View.extend({
events: {
'click .foo': 'fooClicked'
},
fooClicked: function(e) {
e.preventDefault();
console.log('.foo clicked');
}
});
new MyViewClass({el: $('#myView')});
</script>
</body>
</html>
I am building a Spotify App with four tab pages. The content of all tabs are loaded on initial load of the app. Each tab contain one or more playlists that are being populated with data from 3rd party web apis that are resolved into spotify tracks.
The selected tab works fine. the playlist show up a expected. The problem is with tabs that are initially hidden but later selected. Here the playlist looks like this when selected:
not fully rendered playlist
Looking in the Inspector I can see that the content has not yet rendered:
<div class="sp-list sp-light" tabindex="0">
<div style="height: 100px; ">
</div>
</div>
When I do a resize of the Spotify desktop app, the playlist is finally rendered:
rendered playlist after resize
To populate the playlist I use the 'standard' spotify models and views:
var playlist = new views.List(tempPlaylist);
//where tempPlaylist is a new models.Playlist();
//that has been populated with tempPlaylist.add(search.tracks[0].uri);
playerPlaylistDiv.append(playlist.node);
I am only seing this issue when using tabs. When displaying all content on one long page all playlists are fully rendered. I wonder if it has to do with timing: that I am hiding content that has not yet fully rendered? Any thoughts much appreciated.
I handle tab changes this way:
/* Handle URI arguments */
models.application.observe(models.EVENT.ARGUMENTSCHANGED, tabs);
/* Handle tab changes */
function tabs() {
var args = models.application.arguments;
// Hide all sections
$('section').hide();
// Show current section
$("#" + args[0]).show();
}
FYI I am using the Spotify preview 0.8.10.3.
I am not sure this is the same thing, but I ran into similar issues trying to create tracklistings from playlist-uris on the fly; also couldn't track it down any closer (the containing DOM was certainly rendered and ready); and it only happened on certain playlists, never e.g. on albums.
I was able to circumentvent this problem by "cloning" playlist - obviously there's a "performance" hit ...
// assuming uri is the playlist's URI
models.Playlist.fromURI( uri, function(originalPlaylist) {
var tempPlaylist = new model.Playlist();
$.each(originalPlaylist.tracks, function(t) { tempPlaylist.add(t); });
var tracklist = new views.List(tempPlaylist);
// etc...
}
I am not sure what's on here, but maybe that helps you along :)
PS. Also - make sure you have a doctype-declaration in index.html (), the spotify client does some weird things if you don't.
The solution I've found is this:
I arrowed it down to being an issue with showing/hiding the content since showing the full content without tabs never causes issues. So instead of using .show()/.hide() I now hide and show the content by setting the height of the sections to 100%/0:
// Hide all other sections
$("section#" + args).siblings().height('0');
// Show current section
$("section#" + args).height('100%');
Not sure why this works, but it does (for me at least).
I had the same problem (see Spotify List objects created from localStorage data come up blank) and fixed it by doing the hide()/show() of divs before any processing. Previously I was constructing the playlist and then show()ing the div after which led to a blank list.
I think I've actually managed to solve this and I think it's bulletproof.
Basically I was trying to solve this by trying to convince the API that it needed to redraw the playlist by hiding things/scrolling things/moving things which worked occasionally but never consistently. It never occurred to me to change the playlist itself. Or at least make the API think the playlist has changed.
You can do so by firing an event on the Playlist object.
var models = sp.require('$api/models');
...
// playlist is your Playlist object. Usually retrieved from models.Playlist.fromURI
playlist.notify(models.EVENT.CHANGE, playlist);
These are just standard Spotify functions and the list updates because it thinks something has changed in the playlist. Hope this helps someone!
Putting this code in
$('#hello').click ->
alert 'hello'
in posts.js.coffee in vanilla Rails 3.1 app does not work. The javascript is compiled and loaded before the page so the function isn't bound to its element. There are easy solutions, like manually loading the js on the page rather than using the asset pipeline, or using JQuery .live functions, but it seems like this code should work out of the box. Am I missing something??
I might be pointing out the obvious here, but have you (in jQuery) tried this:
$(function(){
//your code
$('#hello').click(function(){
alert("hello");
});
});
or
$(document).ready(function(){ [...] });
These (atleast under normal circumstances) should prevent any javascript inside from doing anything until the DOM has been loaded.
Hope this helps
I've been working on an API in Node.js for the first time, and of course I needed a test page so I decided to whip one up in Node as well for the hell of it.
After wracking my mind to come up with a good way to load the header, body and footer files (Jade syntax files) and have them be friends and render together, I came up with a recursive solution.
function assemblePage(name,markup)
{
markup = markup || '';
if (markup=='')
fs.readFile('header.jade', function(err,data){assemblePage(name,markup+data)});
else if (name != 'footer')
fs.readFile(name+'.jade', function(err,data){assemblePage('footer',markup+data)});
else
fs.readFile('footer.jade', function(err,data){console.log(markup+data);__res.send(jade.render(markup+data))});
}
So all I have to call is:
assemblePage('home');
Is this the best way to go about things?
I think you should be using expressjs(High performance, high class web development for Node.js) to render your templates.
It has a very sophisticated View Rendering. I think what you need is called view partials. In the screencasts section you can watch a screencast about view partials