I'm doing a simple AJAX call to append an album's tracks in an unordered list. It will append the tracks on the second click with this code:
window.app.views.AlbumView = Backbone.View.extend({...
events: {
'click .queue-add' : 'selectAlbum',
'click .show-tracks' : 'showTracks',
'click .hide-tracks' : 'hideTracks',
},
showTracks: function(){
_this = this
this.model.getTracks().forEach(function(track){
_this.$el.find('.tracks').append("<li>"+track.attributes.title+"</li>");
});
},
Clearly the tracks hadn't been fetched in time for the first click so I added a callback function to the showTracks method like so:
showTracks: function(){
_this = this
this.model.getTracks({
success: function(tracks){
console.log(tracks);
tracks.forEach(function(track){
_this.$el.find('.tracks').append("<li>"+track.attributes.title+"</li>");
});
}
});
},
Yet it won't enter the block and the console.log(tracks); puts nothing to the console.
Any tips would be really awesome here, thanks!!
app.models.Album = Backbone.Model.extend({
....
getTracks: function() {
this.tracks.fetch();
return this.tracks
},
....
});
I couldn't find where did you invoke that callback. you may need modify "getTracks" method like this:
getTracks: function(callback) {
this.tracks.fetch();
callback(this.tracks); //you need to invoke the callback before return
return this.tracks;
}
This is called "callback pattern", google it will find more.
and the backbone model's fetch method accept option argument, It is a object with two keys -- success and error -- both are function. If you provide this argument, backbone will call them automatically.
hope this help.
Related
I need to write a test (in Rails) that just shows a function was called. I am not sure to approach this in Jasmine or in Capybara?
My click event is:
<button class="player_vs_cpu_intro" onclick="playerVsCpu()">Player Vs. CPU's Selection</button>
My function is:
function playerVsCpu() {
alert("Hello World");
//other code is in here as well
}
Also, if I had a function within playerVsCpu();, can I test that as well?
Any advice would be appreciated!
You can use jasmine for that. To check if a function has been called you need to use spyOn().
describe("button click", function() {
var btn;
beforeEach(function() {
btn = $('.player_vs_cpu_intro')[0];
});
it("should call playerVsCpu", function() {
spyOn(window, 'playerVsCpu');
$(btn).click();
expect(window.playerVsCpu).toHaveBeenCalled();
});
});
You can also test if a function has been called inside playerVsCpu(). Let's say you call a function anotherFunction() inside playerVsCpu() and you want to assert that.
describe("playerVsCpu", function() {
it("should call anotherFunction", function() {
spyOn(window, 'anotherFunction');
playerVsCpu();
expect(window.anotherFunction).toHaveBeenCalled();
});
});
I have an MVC PagedList which works just fine. I am filtering that list and the filter predicate is sent to the client during roundtrips. I use unobtusive ajax replacing. My pager code looks as:
#Html.PagedListPager((IPagedList)Model.Items,
page => Url.Action("Filter",
new ClientSearch
{
Page = page,
PageSize = Model.PageSize,
Predicate = Model.Predicate
}),
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(
new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "clients-list",
}))
The problem is, that the Predicate parameter is too long. And it should be. I get the following exception:
"The request filtering module is configured to deny a request where the query string is too long."
I do not want to alter the web.config in order to allow long parameters. I would like to pass the model in a POST header instead of query string parameter. Is it possible with PagedList?
Thanks in advance.
I still couldn't figure out whether PagedList supported posting large data, however I ended up with the following workaround.
I have a post method which posts the model to the controller function and replaces the partial view content with the results.
function postToPage(url, size, predicate, replace) {
var data = {
size: size,
predicate: predicate
};
$.ajax({
url: url,
data: data,
type: 'POST',
success: function (result) {
$('#' + replace).html(result);
}
});
}
I also have another function to replace the URLs in the pagination-container div and wire up the click event to call the post method. The click event stops event propagation, so the URL in the href attribute won't be used.
function replaceHrefs() {
$('div[class = pagination-container').find('a').each(function (index, value) {
var url = value.href.toString();
value.addEventListener('click', function (event) {
event.stopPropagation();
post(url);
});
value.href = '#';
});
I created a custom version of post method in order to generate the pagesize and predicate from the model.
function post(url) {
postToPage(url, #Model.PageSize, '#Model.Predicate', 'clients-list');
}
I had to wire up the URL replacing procedure to two places: when the document becomes ready and when the ajax call completes. These covered all the cases I needed.
$( document ).ajaxComplete(function() {
replaceHrefs();
});
$( document ).ready(function() {
replaceHrefs();
});
I hope it helps someone.
Using the custom bootstrap plugin for typeahead functionality
https://gist.github.com/1891669
How to attach a callback for 'select' event?
The following code doesn't work.
var selectedFn = $('.typeahead dropdown-menu').on('select', function( ev ){
console.log(ev);
});
Can someone explain how this works?
A new way of doing this is:
$('.input').typeahead({
// snip
}).on('typeahead:selected', function() {
// on selected
});
$('#myselector').typeahead({
itemSelected:function(data,value,text){
console.log(data)
alert('value is'+value);
alert('text is'+text);
},
//your other stuffs
});
You have to just pass itemSelected in the callback function and it will give you the selected item.
Hope this will work for you.
You can just listen to your inputs change event like this:
$('input.typeahead').on('change', function () { ... })
Specify the arguments in the function that handles the event in order to get the value selected as suggested in the documentation at https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md#custom-events
.on('typeahead:select', function(ev,value) {
//value = the selected object
//e.g.: {State: "South Dakota", Capital: "Pierre"}
})
It gives exactly the same result with typeahead:select instead of typeahead:selected. I'd rather go with the one which is documented.
$('.typeaheadGroupSelect').typeahead({
// snip
}).on('typeahead:selected', function(data, value, text) {
// on selected
console.log(data);
console.log(value.idPublic); // here you can access all json object by using value.key
console.log(value.name);
});
I used above code snippet to access data from the selection and assign certain hidden values to another input.
Prior I added an object to the data source typeahead is using to query data, see below:
var jsonData = [
{"id":"1","idPublic":"978343HFJ","name":"Volkswagen Group Sales International"},
{"id":"2","idPublic":"8343JJR98","name":"BMW Group Sales APAC"},
{"id":"3","idPublic":"935723JFF","name":"Jaguar Group Sales Asia"},
{"id":"4","idPublic":"3243JFUFF","name":"Mercedes Benz Group Sales Europe"}
];
In my web app , I am showing rates of stocks.I am using jquery autocomplete to show options while entring stocks name. But I have built local copy of javascript array. I want to show the options from this local array , If search term is not found in local array then ajax call must be made to get the list from server side.
Thanks !!!
//Local array
var local_array=["option1","option2"];
//jqueryUI call of autocomplete function
$('#search_stock').autocomplete({
source:function(){
if(search term is found in local array)
{
show suggestion from local array.
}
else
{
make ajax call to show suggestions of stock names.
}
}
});
UPDATE
Here's the actual code
$(function() {
var cache = {'option1':'option1','option2':'option2'}, lastXhr;
$( "#stock_rates" ).autocomplete({
minLength: 2,
source: function( request, response ) {
var term = request.term;
if ( term in cache ) {
response( cache[ term ] );
return;
}
lastXhr = $.getJSON( "stock_rates.php", request, function( data, status, xhr ) {
cache[ term ] = data;
if ( xhr === lastXhr ) { response( data ); }
});
}
});
});
The example pages for jQuery UI autocomplete have an example of exactly this issue.
http://jqueryui.com/demos/autocomplete/#remote-with-cache. Click the 'View Source' link on that page to see the code for the example.
The key part is that 'source' takes arguments.
source: function(request, response){
You need to read request, either fetch the value from your cache, or do a request, and then call the response function and pass it the matched values.
Update
Your problem now is that the format that you are storing in your cache is wrong. The cache just stores data as it would be returned from your getJSON call, indexed by the search term. It is up to you do to do the prefix checking and such.
To continue the way you are trying now, you'll either need to populate the cache properly.
var cache = {
"o": ['option1', 'option2'],
"op": ['option1', 'option2'],
// ....
"option1": ['option1'],
"option2": ['option2']
};
Otherwise, you could store the data differently and put more logic in your 'source' function to do the prefix checking on a static array or something. That all really depends on the data you are caching though.
Use search event of autocomplete and check your condition in that event and based on that return true or false if you want to make a ajax call respectively.
Below is the sample code.
$('#search_stock').autocomplete({
search:function(event,ui){
if(search term is found in local array)
{
return false;
}
else
{
return true;
}
}
});
I have this site that i am working on that i need to figure out when the last ajax call is finished...I am using this jQuery plugin and all works great but the problem is the client uploads 2 files at a time... and i need to redirect to another page after the last ajax call. If you look the it in firebug while uploading files it run http://dev.posnation.com/test/j/example/upload.php twice and i need to have the page redirect after and only after the second run..is there a way in javascript or jQuery to tell if the ajax calls are complete.
Here is the code that instantiates it
// Initialize the jQuery File Upload widget:
$('#fileupload').fileupload();
and there is a onDone function in the jQuery.fileupload.js
_onDone: function (result, textStatus, jqXHR, options) {
but its running after the first run not after both files are uploaded....any ideas on how i can redirect to another page after both files are uploaded....thanks in advance
the short answer is to decrement a counter in the onDone callback. one possible implementation would be to use a global variable as illustrated below:
var numberFilesToUpload = 2;
// code to upload file
onDone: function() {
// this is the upload plug-ins callback function
numberFilesToUpload--;
if (numberFileToUpload == 0) {
windows.location.href = "/uploading-finished";
}
}
there are more elegant solutions, but they will all involve decrementing a counter.
You could use closure to produce the function which has a local records for files have uploaded.
var fileUploads = function (filesNum, callback) {
var numberFilesToUpload = filesNum;
// code to upload file
return function() {
// this is the upload plug-ins callback function
numberFilesToUpload--;
if (numberFileToUpload == 0) {
callback();
}
};
}(2, function () {
//what you want to do when files are all uploaded.
});
fileUploads will fire the callback function after 2 files are uploaded. The callback and filelimits are specified in this line
var fileUploads = function () {
//...
} (2, function () {});