I'm pretty new to Backbone and I've been trying to create autocomplete functionality with it, fed by an ASMX webservice. The issue I seem to have is whilst my webservice returns in JSON (after a painful battle with it), it wraps the response in a 'd' (dataset). How do I get the view to understand this and get at the correct data?
Here is my code:-
var Airline = Backbone.Model.extend({
initialize: function () {},
defaults: {
name: 'Airline Name',
rating: 50,
icon: '/blank.png'
}
});
var AirlineCollection = Backbone.Collection.extend({
model: Airline,
contentType: "application/json",
url: '/ControlTower/public/runway.asmx/all-airlines',
parse: function (response) {
return response;
}
});
var SelectionView = Backbone.View.extend({
el : $('#airline'),
render: function() {
$(this.el).html("You Selected : " + this.model.get('AirlineName'));
return this;
},
});
var airlines = new AirlineCollection();
airlines.fetch({async: false, contentType: "application/json" });
var airlineNames = airlines.pluck("AirlineName");
$("#airline").autocomplete({
source : airlineNames,
minLength : 1,
select: function(event, ui){
var selectedModel = airlines.where({name: ui.item.value})[0];
var view = new SelectionView({model: selectedModel});
view.render();
}
});
Can anyone see what I'm doing wrong? I've been sitting here for too long now!
Help is appreciated ;)
What about in your AirlineCollection:
parse: function (response) {
return response.d;
}
This works for me
In AirlineCollection
parse: function (response) {
var data = (typeof response.d) == 'string' ? eval('(' + response.d + ')') : response.d;
return data;
}
Related
I am a beginner and learning web development. In my sample project I have created Pie Chart using ChartJS. I am getting data from REST Service. Everything is working fine and pie chart is getting rendered properly. The problem is when there is null data from REST then I am getting error in Chart.js.
Error:
JSON DATA FROM REST:
My sample project uses BackboneJS. I know the error is because there is no data coming from REST. How can I handle that so that m Pie Chart does not crash.
Below is the MODEL:
define(['backbone'], function(Backbone) {
var chart = Backbone.Model.extend({
urlRoot: 'SAMPLE REST URL',
defaults: function() {
return {
currMonthOccAvailVac: [],
};
},
fetch: function(data) {
var d = $.Deferred();
var self = this;
var ajaxRequest = $.ajax({
url: this.urlRoot,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(data)
});
ajaxRequest.done(function(json) {
var graphVar = {
currMonthOccAvailVac: [],
}
var yearSelected = (localStorage.getItem('date')).split("-")[0];
var monthSelected = (localStorage.getItem('date')).split("-")[1];
for (var i = 0; i < json.length; i++) {
var monthYear = json[i].columnstrDate.split("/");
var year = monthYear[0];
var month = monthYear[1];
if(month.length == 1)
if(month == (monthSelected - 1) && year == yearSelected)
{
graphVar.currMonthOccAvailVac.push(json[i].columndecOccPercentage);
graphVar.currMonthOccAvailVac.push(json[i].columndecVacantUnitsPercentage);
graphVar.currMonthOccAvailVac.push(json[i].columndecUnavailableUnitsPercentage);
}
}
self.set({
currMonthOccAvailVac: graphVar.currMonthOccAvailVac,
});
d.resolve();
});
//failure callback for ajax request.
ajaxRequest.fail(function(jqXHR, status) {
// Handle fail request
d.reject();
});
return d.promise();
}
});
// returning the model
return {
chart: chart
};
});
Place in ChartJS where actually code is breaking:
So how can I make sure even if graphvar.currMonthOccAvailVac has no value the pie chart does not crash. Kindly guide me.
EDIT
Currently in my View Model I did something like below. But I am not sure if this the right way to handle.
define(['backbone'], function(Backbone) {
var sixthSubViewModel = Backbone.View.extend({
template: _.template($('#myChart6-template').html()),
render: function() {
$(this.el).html(this.template());
var ctx = this.$el.find('#pieChart')[0];
var data = {
datasets: [{
data: this.model.attributes.currMonthOccAvailVac,
label: 'My dataset' // for legend
}],
labels: [
"Rented",
"Vacant",
"Unavailable",
]
};
// I AM CHECKING HERE THE LENGTH AND THE RNEDERING THE PIE CHART
if (this.model.attributes.currMonthOccAvailVac.length > 1)
var pieChart = new Chart(ctx, {
type: 'pie',
data: data,
otpions: {
legend: false
}
});
WHAT SHALL I PUT IN THE ELSE PART
},
initialize: function() {
this.render();
}
});
return sixthSubViewModel;
});
Is there any way to create your own ajax method to make a POST request instead of using save ?
Save not only fires the AJAX request but triggers events and validation, so I wouldn't write my "own" save method.
However, you can always write a model function like:
var SomeModel = Backbone.Model.extend({
urlRoot: "/some/url",
altSave: function () {
$.post(this.urlRoot, {
/*assemble your post data*/
}, function (response) {
});
}
});
var s = new SomeModel();
s.altSave();
calling s.altSave(); will fire a POST request.
That's right and it works but I think this is a better solution:
'use strict';
define([
'underscore',
'backbone',
'config/appConfig'
],function(_,Backbone,Config){
var StatsModel = Backbone.Model.extend({
urlRoot: Config.urlStats,
url: function() {
var url = this.urlRoot + "/resource";
return url;
},
defaults: {
metricID: '',
groupByID: ''
},
requestStats: function(opts) {
var url = this.url(),
options = {
url: url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(this.attributes)
};
_.extend(options, opts);
return (this.sync || Backbone.sync).call(this, null, this, options);
}
});
return StatsModel;
});
Thank you very much
I'm almost there and on my first jquery autocomplete script... I just need some help to figure out how to return the founded elements has link so that we can click on them.
Here a part of my js code:
$(document).ready(function() {
var attr = $('#leseulsteve_lieuxbundle_lieutype_nom').attr('data-url');
var searchRequest = null;
$("#leseulsteve_lieuxbundle_lieutype_nom").autocomplete({
minLength: 3,
source: function(request, response) {
if (searchRequest !== null) {
searchRequest.abort();
}
searchRequest = $.ajax({
url: attr,
method: 'get',
dataType: "json",
data: {nom: request.term},
success: function(data) {
searchRequest = null;
console.log(data);
$.each(data, function (i, v) {
--- SOME VARIABLE I GUESS TO STORE THE RESULT ---
});
return THE 'SOME VARIABLE;
}
}).fail(function() {
searchRequest = null;
});
}
});
});
In the console I got this from the console.log(data) line:
Object {École secondaire De Rochebelle: "/GestigrisC/app_dev.php/lieux/voir/2", École secondaire la Camaradière: "/GestigrisC/app_dev.php/lieux/voir/3"}
I have control over how the JSON feed is built, so no worries there if it's helps to build that super mysterious for me now variable to return.
Thanks a lot for the help!
If you just want to build links and put them into your HTML then I think you're looking for something like this:
success: function(data) {
var html = '';
$.each(data, function (i, v) {
html += ''+i+'';
});
$('#container_id').html(html);
}
Got it right, thanks for your help :)
$(document).ready(function() {
var attr = $('#leseulsteve_lieuxbundle_lieutype_nom').attr('data-url');
var searchRequest = null;
$("#leseulsteve_lieuxbundle_lieutype_nom").autocomplete({
minLength: 3,
source: function(requete, reponse) {
if (searchRequest !== null) {
searchRequest.abort();
}
searchRequest = $.ajax({
url: attr,
method: 'get',
dataType: "json",
data: {nom: requete.term},
success : function(donnee){
reponse($.map(donnee, function(objet){
return {label: objet.type + ' | ' + objet.label, type: objet.type, id: objet.id};
}));
}
}).fail(function() {
searchRequest = null;
});
},
select: function (event, ui) {
$('#leseulsteve_lieuxbundle_lieutype_nom').val(ui.item.label);
$('#leseulsteve_lieuxbundle_lieutype_type').val(ui.item.type);
$('#leseulsteve_lieuxbundle_lieutype_id').val(ui.item.id);
$('#formulaire').submit();
}
});
});
I have got a task to do user editing. I did this. But i cannot pass the value as json object. How can i join two values.
My first object is
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
}
else {
o[this.name] = this.value || '';
}
});
return o;
};
My second object is
var location = function() {
var self = this;
self.country = ko.observable();
self.state = ko.observable();
};
var map = function() {
var self = this;
self.lines = ko.observableArray([new location()]);
self.save = function() {
var dataToSave = $.map(self.lines(), function(line) {
return line.state() ? {
state: line.state().state,
country: line.country().country
} : undefined
});
alert("Could now send this to server: " + JSON.stringify(dataToSave));
};
};
ko.applyBindings(new map());
});
I want to concatenate this. I tried this but i got an error
$.ajax({
url: '/users/<%=#user.id%>',
dataType: 'json',
//async: false,
//contentType: 'application/json',
type: 'PUT',
data: {total_changes: JSON.stringify(dataToSave) + JSON.stringify($("#edit_user_1").serializeObject())},
//data:JSON.stringify(dataToSave),
//data:dataToSave,
success: function(data) {
alert("Successful");
},
failure: function() {
alert("Unsuccessful");
}
});
When i run this it shows an error like this in terminal.
How can i solve this?
If you have json1 and json2 objects you can do:
$.extend(json1, json2);
So in json1 you will get both objects merged.
The problem is JSON.stringify(…) + JSON.stringify(…). This will create a string like "{…}{…}" which obviously is invalid JSON (that's where you get the JSON::ParserError from).
I'm not sure what you are trying to accomplish and which JSON structure your server expects, but you could do something like
…
contentType: 'application/json',
data: JSON.stringify( {
total_changes: dataToSave,
edits: $("#edit_user_1").serializeObject()
}),
…
The following code works great with a hardcoded array (initialData1), however I need to use jquery .ajax (initialData) to initialize the model and when I do the model shows empty:
$(function () {
function wiTemplateInit(winame, description) {
this.WIName = winame
this.WIDescription = description
}
var initialData = new Array;
var initialData1 = [
{ WIName: "WI1", WIDescription: "WIDescription1" },
{ WIName: "WI1", WIDescription: "WIDescription1" },
{ WIName: "WI1", WIDescription: "WIDescription1" },
];
console.log('gridrows:', initialData1);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{UserKey: '10'}",
url: "WIWeb.asmx/GetTemplates",
success: function (data) {
for (var i = 0; i < data.d.length; i++) {
initialData.push(new wiTemplateInit(data.d[i].WiName,data.d[i].Description));
}
//console.log('gridrows:', initialData);
console.log('gridrows:', initialData);
}
});
var viewModel = function (iData) {
this.wiTemplates = ko.observableArray(iData);
};
ko.applyBindings(new viewModel(initialData));
});
I have been trying to work from the examples on the knockoutjs website, however most all the examples show hardcoded data being passed to the view model.
make sure your "WIWeb.asmx/GetTemplates" returns json array of objects with exact structure {WIName : '',WIDescription :''}
and try using something like this
function wiTemplateInit(winame, description)
{
var self = this;
self.WIName = winame;
self.WIDescription = description;
}
function ViewModel()
{
var self = this;
self.wiTemplates = ko.observableArray();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{UserKey: '10'}",
url: "WIWeb.asmx/GetTemplates",
success: function (data)
{
var mappedTemplates = $.map(allData, function (item) { return new wiTemplateInit(item.WiName, item.Description) });
self.wiTemplates(mappedTemplates);
}
});
}
var vm = new ViewModel();
ko.applyBindings(vm);
If you show us your browser log we can say more about your problem ( Especially post and response ). I prepared you a simple example to show how you can load data with ajax , bind template , manipulate them with actions and save it.
Hope this'll help to fix your issue : http://jsfiddle.net/gurkavcu/KbrHX/
Summary :
// This is our item model
function Item(id, name) {
this.id = ko.observable(id);
this.name = ko.observable(name);
}
// Initial Data . This will send to server and echo back us again
var data = [new Item(1, 'One'),
new Item(2, 'Two'),
new Item(3, 'Three'),
new Item(4, 'Four'),
new Item(5, 'Five')]
// This is a sub model. You can encapsulate your items in this and write actions in it
var ListModel = function() {
var self = this;
this.items = ko.observableArray();
this.remove = function(data, parent) {
self.items.remove(data);
};
this.add = function() {
self.items.push(new Item(6, "Six"));
};
this.test = function(data, e) {
console.log(data);
console.log(data.name());
};
this.save = function() {
console.log(ko.mapping.toJSON(self.items));
};
}
// Here our viewModel only contains an empty listModel
function ViewModel() {
this.listModel = new ListModel();
};
var viewModel = new ViewModel();
$(function() {
$.post("/echo/json/", {
// Data send to server and echo back
json: $.toJSON(ko.mapping.toJS(data))
}, function(data) {
// Used mapping plugin to bind server result into listModel
// I suspect that your server result may contain JSON string then
// just change your code into this
// viewModel.listModel.items = ko.mapping.fromJSON(data);
viewModel.listModel.items = ko.mapping.fromJS(data);
ko.applyBindings(viewModel);
});
})