If I loop the collection in the view, it's seems empty, alert dialog don't show up. When I use console.log(this.collection) in this view, it's look ok (16 element in this collection).
My router: (collection url: '/api/employees', this is a rails json output)
Office.Routers.Employees = Backbone.Router.extend({
routes: {
"": "index"
},
initialize: function() {
this.collection = new Office.Collections.Employees();
this.collection.fetch();
},
index: function() {
var view = new Office.Views.EmployeesIndex({ collection: this.collection });
view.render();
}
});
and my index.js view:
Office.Views.EmployeesIndex = Backbone.View.extend({
render: function() {
this.collection.each( function( obj ){ alert(obj); } );
}
});
Edit:
This is the output of the console.log(this.collection) in view : http://i.stack.imgur.com/ZQBUD.png
Edit2:
I thing Rails is the guilty. When I work whit static collection, everything works fine
var collection = new Backbone.Collection([
{name: "Tim", age: 5},
{name: "Ida", age: 26},
{name: "Rob", age: 55}
]);
collection.fetch() makes an asynchronous request to the server. The index callback doesn't wait for the fetch to return. So your render function is rendering an empty collection.
You need to use the success callback of the fetch method:
index: function() {
this.collection.fetch({
success: function(data) {
var view = new Office.Views.EmployeesIndex({ collection: data });
view.render();
}
});
}
Note that the Backbone documentation recommends bootstrapping any initial data you need by including the data in the document itself:
When your app first loads, it's common to have a set of initial models
that you know you're going to need, in order to render the page.
Instead of firing an extra AJAX request to fetch them, a nicer pattern
is to have their data already bootstrapped into the page.
The fetch has probably not completed by the time your view renders. Try the following:
index: function() {
var p, collection, view;
collection = new Office.Collections.Employees();
p = collection.fetch();
view = new Office.Views.EmployeesIndex({ collection: collection });
p.done(view.render);
}
Related
I am new to backbone and am using backbone in my rails application . This is what I am doing in my application
I am using Backbone Paginator for pagination support in my application as well using Gmaps for rendering locations on gmaps , for each time I am displaying 5 records from the server with pagination and displaying corresponding 5 location in map view , so now I need to show the remaining locations on map when I click on paginated links (prev page , next page) , I think I need to write some click events , but I am not sure where to write and how to write this events , Can any one please help me . please review the code below I have written evnets but those are not working
Thanks in advance
var Listings = Backbone.PageableCollection.extend({
model: Bdemo.Models.Listing,
mode: "server" ,
url: '/listings' ,
events: {
"click #paginationSelect" : "fetchSelectedData"
},
fetchSelectedData: function(){
console.log("CAMEEEEEEEEEEEEEEEEEEEEEEEEEEE")
},
// Initial pagination states
state: {
pageSize: 3,
/* sortKey: "updated",*/
order: 1
},
queryParams: {
totalPages: null,
totalRecords: null,
sortKey: "sort"
},
parseState: function (resp, queryParams, state, options) {
return {totalRecords: resp.total_pages};
},
parseRecords: function (resp, options) {
return resp.listings;
}
});
#ratnakar:
All you need is events function. Set an id for each of your paginated links. Then include the events function. I hope that you're developing SPA(single page application). With that note assume the following settings.
In the homeview.js("templates" folder) page include the paginated links enclosed by the footer tag.
<footer>
<button id="prevPage">previous</button>
<button id="nextPage">next</button>
</footer>
then the go to the corresponding homeview.js view file("views" folder)
backboneApp.Views.homeview = Backbone.View.extend({
//Default "events" function for handling delegate events.
events:{
//catching click events
"click #prevPage" : "goPrevious" //on click of DOM which has id as prevPage, calling a function goPrevious.
"click #nextPage" : "goNext" //same as above call goPrevious function.
},
//Defining the user created function goPrevious and goNext.
goPrevious: function(){
//Make your server call here.... for the previous 5 records.
},
goNext: function(){
// server call here for the next 5 records.
}
});
Thus the basic idea of using delegate events for paginated links is defined above.
From your question I understand that you are using backgrid-paginator in server mode.
Binding to the click event won't work, because you need to make sure that the models have been fetched from the server before you can access their data.
You can bind to your collections' request event and act on the xhr.done()
In your view:
initialize: function() {
this.listenTo(this.record_collection, "request", this.onCollectionRequested);
},
onCollectionRequested: function(collection, xhr, options) {
_this = this;
xhr.done(function(){
_this.showRecordLocationsOnMap(collection);
})
},
showRecordLocationsOnMap: function(records) {
/* Update your map here */
}
Hi finally solved this by calling my own function(callGmap) from Backbone.PageableCollection , here is my new code
var Listings = Backbone.PageableCollection.extend({
model: Bdemo.Models.Listing,
mode: "server" ,
url: '/listings' ,
events: {
"click #paginationSelect" : "fetchSelectedData"
},
fetchSelectedData: function(){
console.log("CAMEEEEEEEEEEEEEEEEEEEEEEEEEEE")
},
// Initial pagination states
state: {
pageSize: 3,
/* sortKey: "updated",*/
order: 1
},
queryParams: {
totalPages: null,
totalRecords: null,
sortKey: "sort"
},
parseState: function (resp, queryParams, state, options) {
return {totalRecords: resp.total_pages};
},
parseRecords: function (resp, options) {
callGmap(resp.hash);
return resp.listings;
}
});
I have a couple of variations on the ajax depending on the flow of interactions on the page. But it's only the variables that changes. here is one of them:
$('#btn_skickaEnkel').bind('click', function () {
$.ajax({
type: 'POST',
url: '/Contact/IntresseAnmälan/',
dataType: 'json',
data: {
Namn: $('#namn').val(),
Mail: $('#mail').val(),
Info: $('#meddelande').val(),
Nivå: $('#nivå').find(":selected").text(),
IsEnkel: true,
Telefon: $('#nr').val(),
ID: function () {
var url = window.location.pathname;
var id = url.substring(url.lastIndexOf('/') + 1);
return id;
}
},
traditional: true
});
});
In my controller i am unable to redirect or return a different view. At this point the data from JSON is no longer relevant because it's already been saved to DB.
My Controller:
public ActionResult IntresseAnmälan(BokningContainer bokning)
{
db = new DbContext();
//Saving some data to database(removed)
//Just determening the state of container obj.
if (bokning.IsEnkel)
{
//Geting som information from db (removed)
//Creating a mail (removed)
email.Send(bokning.Namn, bokning.Mail, body);
}
else
{
}
//db.SaveChanges();
//This part is not working, I think it's beacuase of the Ajax
return View("IntresseAnmälan");
}
The view is not rendered and I think it's related to the ajax. The view is simply not rendered. Is there some way to force returning it and ignoring the ajax? As I said the data is no longer needed because the content is already saved to the DB.
You cannot render view on ajax call,simply you can use form post method or just redirect it to desired action on "succcess" of ajax call as below:
$('#btn_skickaEnkel').bind('click', function () {
$.ajax({
type: 'POST',
url: '/Contact/IntresseAnmälan/',
dataType: 'json',
data: {
Namn: $('#namn').val(),
Mail: $('#mail').val(),
Info: $('#meddelande').val(),
Nivå: $('#nivå').find(":selected").text(),
IsEnkel: true,
Telefon: $('#nr').val(),
ID: function () {
var url = window.location.pathname;
var id = url.substring(url.lastIndexOf('/') + 1);
return id;
}
},
traditional: true,
success: function(result) {
window.location.href = '#Url.Action("action", "Controller")';
}
});
});
I couldn't believe my eyes when I figured out this "Bugg". The problem was that I, at some point, changed the submit to a button. So the form was never submiting. Well, at least I learnt a bit about views and Ajax.
Sorry for taking your time.
I'm using jquery-ui autocomplete on a page I'm creating. On the same page I have some ajax events going on. During the other ajax events I'm adding an overlay to my page, so that all the links on the website aren't clickable anymore for the user. I don't want that to happen during the autocomplete.
autocomplete:
$(function() {
$( "#search_input" ).autocomplete({
source: '/search_autocomplete/',});
});
ajax:
$.ajax({
url: "/ajax_login/",
login_user: $("#login_user").val(),
password: $("#login_password").val(),
});
ajaxStart:
$("#loading_gif").ajaxStart(function() {
$("#overlay").show();
$(this).show();
});
To prevent the ajaxstart function from being executed during the ajax events where it's not necessary. I add
global:false,
to the corresponding ajaxfunctions. How can I do something similar during the autocomplete without changing the jquery-ui source?
For this you have to omit the shorthand call with source and change the call like this.
$('#search_input').autocomplete({
source: function (request, response) {
var DTO = { "term": request.term };
//var DTO = { "term": $('#search_input').val() };
$.ajax({
data: DTO,
global: false,
type: 'GET',
url: '/search_autocomplete/',
success: function (jobNumbers) {
//var formattedNumbers = $.map(jobNumbersObject, function (item) {
// return {
// label: item.JobName,
// value: item.JobID
// }
//});
return response(jobNumbers);
}
});
}
//source: '/search_autocomplete/'
});
The advantage of this long-hand method is
You can pass more than one parameter. Also the parameter name should not have to be term.
The short-hand notation expects an array of strings. Here you could return an array of objects also.
If you want $.ajax() to work a certain way most of the time but now all the time, then you probably shouldn't change its default behavior.
I recommend creating a function that wraps an ajax request in a function that enables and disables the overlay at the appropriate times. Call this function where you want the overlay to be used, and use plain $.ajax() for your autocomplete.
I would agree that naveen's answer is the best solution. In my case the vast amount of code that would require changing wasn't cost effective as we're in the process of doing a re-write and we needed a short term solution.
You can override the ajax call in jQuery UI, I copied the source for the _initSource function call that handles the AJAX request. Then simply added the global: false to the $.ajax options. The code here is based on jquery-ui 1.9.2, you may have to find the correct source for your version.
$.ui.autocomplete.prototype._initSource = function () {
var array, url,
that = this;
if ( $.isArray(this.options.source) ) {
array = this.options.source;
this.source = function( request, response ) {
response( $.ui.autocomplete.filter( array, request.term ) );
};
} else if ( typeof this.options.source === "string" ) {
url = this.options.source;
this.source = function( request, response ) {
if ( that.xhr ) {
that.xhr.abort();
}
that.xhr = $.ajax({
url: url,
data: request,
dataType: "json",
global: false,
success: function( data ) {
response( data );
},
error: function() {
response( [] );
}
});
};
} else {
this.source = this.options.source;
}
};
I am using: VS 2010, ASP.NET MVC2, jqGrid 3.8.2.
I want to have the navGrid 'Edit' button open a different view in the controller. I have tried a number of things to no avail. In order to open the selected row, I assume I will need to append the id to the url.
jQuery('#listComponents').jqGrid({
url: '/Components/Get',
editurl: '/Components/Edit',
...
}).navGrid('#pagerComponents', {edit:true, ...}, {url: '/Components/Edit'});
Any suggestions are welcome. If I can't get it to work, I will add an 'Edit' button outside the jqGrid and do a normal Html.ActionLink call to open the different view.
Thanks!
Update
Following #Oleg's answer, I now have the following working perfectly:
jQuery('#listComponents').jqGrid(
{
url: '/Components/Get/',
...
}).navGrid('#pagerComponents', { edit: false, ...})
.navButtonAdd('#pagerComponents', {
caption: "",
title: "Edit Component",
buttonicon: "ui-icon-pencil",
onClickButton: function () {
var id = jQuery("#listComponents").getGridParam('selrow');
if (id) {
var data = jQuery("#listComponents").getRowData(id);
window.location = '/Components/Edit/' + data.COMPONENTID;
}
else {
alert("Please select a row to edit.");
}
}});
The option {edit:true, ...} of the navGrid follow to the usage of editGridRow method of the form editing, so the dialog will be displayed and not the View of your MVC controller. To have the behavior which you want you should use {edit:false, ...} setting and add custom button which look exactly like the original "Edit" button. To make this you should use buttonicon: "ui-icon-pencil" parameter (see editicon default parameter in the navGrid source code). In this answer you will find code example. You can additionally use $.jgrid.nav.edittitle as the title parameter:
var grid = $("#listComponents");
grid.jqGrid({
url: '/Components/Get',
editurl: '/Components/Edit',
...
});
grid.navGrid('#pagerComponents', {edit:false, ...}, ...);
grid.jqGrid ('navButtonAdd', '#pagerComponents',
{ caption: "", buttonicon: "ui-icon-pencil", title: $.jgrid.nav.edittitle,
onClickButton: function() {
var rowid = grid.jqGrid('getGridParam', 'selrow');
window.location = '/Components/Edit/' + 'rowid';
}
}
);
public ActionResult DoSomething(string[] arr, bool someBool, int someInt) { }
trying to call the above method from jQuery:
var test = [];
test.push('dog');
test.push('cat');
$container.load('MyController/DoSomething',
{ 'arr[]': test, 'someBool': true, 'someInt': 1 },
function(response, status, xhr) {
// ...
});
the array paramater is null, other params are fine. What am I doing wrong?
Chrome developer tools shows form data being submitted as
arr%5B%5D%5B%5D:dog
arr%5B%5D%5B%5D:cat
someBool:true
someInt:1
not sure whats going on there but doesn't look right to me
If you are using jquery 1.4 you might need to set the traditional parameter to true in order to be compatible with the default model binder format in ASP.NET MVC:
var test = [];
test.push('dog');
test.push('cat');
$.ajax({
url: 'MyController/DoSomething',
type: 'GET',
traditional: true,
data: { arr: test, someBool: true, someInt: 1 },
success: function(result) {
$container.html(result);
}
});
or if you prefer the .load() method:
var data = { arr: test, someBool: true, someInt: 1 };
$container.load('MyController/DoSomething', $.param(data, true),
function(response, status, xhr) {
// ...
});
Just remove []
{ 'arr': test, 'someBool': true, 'someInt': 1 },
Posted values (checking with Firebug).
arr[] dog
arr[] cat
someBool true
someInt 1
Example on jsFiddle
can you see if this problem is similar to yours:
Passing an nested arrays to asp.net mvc using jQuery's $.ajax
Even i was facing error, in passing array from HTML page to aspx page.
my requirement was to load the aspx page in a DIV tag of the html page. on the page load i need to pass these JS array values to aspx page load.
i used below method.
$('#<divTagID>').load("Targetpage.aspx",{"Arr":JSArrValues});
In aspx page load event i can access this values as:
string results = Response["Arr[]"];
Thanks to JQuery API documentation enter link description here and stackoverflow