backbone model fetch JSON element by ID - javascript

I am using backbone for the first time and I am really struggling to get it to function correctly with a JSON data file.
I have a model Like so:
window.Test = Backbone.Model.extend({
defaults: {
id: null,
name: null,
},
url: function() {
return 'json/test.json/this.id';
},
initialize: function(){
}
});
When a test item is clicked I then try to bring up the details of the pacific model that was clicked by doing
testDetails: function (id) {
var test = new Test();
test.id = id;
test.fetch({ success: function(data) { alert(JSON.stringify(data))}});
},
However this does not work, I am unable to correctly say "get the JSON element with the passed ID"
Can anyone please show me how to correctly structure the models URL to pull the element with the ID.
Thanks

The problem here is that you're treating your JSON data file like a call to a server. That won't work and it's the reason you're getting a 404. If you're accessing a file locally, you have to load the file first. You can do this with jQuery using the .getJSON() method, or if the file's static, just load it into memory with a script block (though you'll probably need to assign a var in the file). Most likely, you'll use jQuery. An example of this can be found here:
Using Jquery to get JSON objects from local file.
If this is an array of JSON, you can load the array into a collection, and use the "at" method to access the particular element by id. If it's entirely JSON, you'll have to create a custom parser.

your url is incorrect for one. you are returning the literal string 'this.id'. you probably want to do something more along the lines of
url: function () {
return 'json/test.json/' + this.id;
}

I would start by fixing your url function:
url: function() {
return 'json/test.json/' + this.get('id');
}
The way you have it now, every fetch request, regardless of the model's id, is going to /json/test.json/test.id

Related

Javascript Passing a Parameter to a Controller

I am trying to call the propDetails function and pass an ID to it. Then pass the same ID to the Static controller but I keep on getting an error: "id = id" (second ID doesn't exist).
I am sorry for this silly question and I can't figure out what I am doing wrong...
function propDetails(id) {
var $detailDiv = $('#detailsDiv'), url = $(this).data('url');
$.get( '#Url.Action("PropDetails", "Static", new { id = id })', function(data) {
$('#detailsDiv').html(data);
});
}
Any guidance would be greatly appreciate.
The id variable is not available in the Razor helper, what you can do is concatenate the id after the Url.Action helper has finished:
function propDetails(id) {
var $detailDiv = $('#detailsDiv'), url = $(this).data('url');
$.get('#Url.Action("PropDetails", "Static")' + id, function(data) {
$('#detailsDiv').html(data);
});
}
In the long run you would want to render a form to serialize your id as part of the request, written as $("form").serialize().
It is much easier to append more fields to an action that uses a complex type as a parameter. Your new code would look as follows:
$.get($detailDiv.find("form").attr("action"),$detailDiv.find("form").serialize(), function(data){
$('detailsDiv').html(data);
});
Your form object would be created in your HTTPGET request in MVC, returning the view with your built #Html.BeginForm() helper, which is part of innerHtml of detailsDiv, that can then be serialized using $("form").serialize()
I hope this is clear and fully answers how to fix the issue. I will modify if it is off base and adds more muddle to the mix of Javascript and MVC.

MVC: Get URL of Method When Using Routing

I found this tutorial on how to build cascading dropdowns in MVC with Razor syntax. I followed the tutorial and got it working perfectly in it's own project. But now that I am trying to port it over to my actual project, I am getting an error when the first dropdown is changed. As per the script, an alert pops up that says:
Failed to retrieve states: [object Object]
I have no idea what [object Object] means. My guess is that the error has something to do with the Url:
url: '#Url.Action("GetStates")
But that's just a guess. The major difference between the example project and the real project is that the real project uses routing for the URL Here's the entire script:
<script src="~/Scripts/jquery-1.10.2.js" type="text/javascript"></script>
<script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"</script>
<script type="text/javascript">
$(document).ready(function () {
//Dropdownlist Selectedchange event
$("#Country").change(function () {
$("#State").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("GetStates")', // we are calling json method
dataType: 'json',
data: { id: $("#Country").val() },
// here we are get value of selected country and passing same value as input to json method GetStates.
success: function (states) {
// states contains the JSON formatted list
// of states passed from the controller
$.each(states, function (i, state) {
$("#State").append('<option value="' + state.Value + '">' +
state.Text + '</option>');
// here we are adding option for States
});
},
error: function (ex) {
alert('Failed to retrieve states: ' + ex);
}
});
return false;
})
});
EDIT AFTER:
While watching the network traffic in Chrome's developer tools, I did this in the stand-alone project that works, and saw this entry with the title "GetStates" and this URL: http://localhost:50266/CustomerFeedback/GetStates.
I did it again in my actual project, and this time I see an entry that says "45/" with this URL: http://localhost:65303/PatientSatisfactionSurvey/45/.
I think this confirms my suspicion that the URL is the problem. I'm going to have to play around with figuring out how to make this URL valid.
Another Edit:
On the project that works, if I go to: http://localhost:50266/CustomerFeedback/GetStates
I get this:
Server Error in '/' Application.
This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.
This is expected as I am trying to hit that actual method. Meaning, I can go to the URL of the method. But when I try and do the same thing in my project: http://localhost:65303/PatientSatisfactionSurvey/GetStates, it just loads the page. That's because it thinks that "GetStates" is a parameter, and not a method.
I CAN NOT figure out what the URL of the method would be!! The dang routing is getting in the way....
routes.MapRoute(
"PatientSatisfactionSurvey",
"PatientSatisfactionSurvey/{ApptID}/{*LanguageCode}",
new { controller = "Forms", action = "PatientSatisfactionSurvey" },
namespaces: new[] { "GEDC.Controllers" }
);
Try changing #Url.Action("GetStates") to:
#Url.Action("ControllerName", "ActionName")
Probbaly something like #Url.Action("PatientSatisfactionSurvey", "GetStates")
which will generate a URL like ~/PatientSatisfactionSurvey/GetStates/5 where 5 is the ID that it is grabbing from the html element with the ID of Country.
Finally worked this out. My problem was three fold. First, when I looked at the HTML source, it turned out this:
url: '#Url.Action("GetStates")', // we are calling json method
was rendering as this:
url: ''
Once I took out the razor syntax, it at least rendered properly in HTML. However, it was still getting the wrong URL. Because the route map I was using had parameters in it, I ended up just creating a whole new route map for this one method:
routes.MapRoute(
"GetStates",
"GetStates",
new { controller = "Forms", action = "GetStates" },
namespaces: new[] { "xyz.Controllers" }
);
Then I changed the URL line in the javascript to look like this:
url: 'GetStates'
But the problem with this was that it was just appending /GetStates to the end of whatever URL I happened to be on. If put the entire fully qualified URL in there, like this...
url: 'http://localhost:65303/GetStates'
That worked. But for obvious reasons, that URL is not a long term solution. So, using this thread, I finally found the answer. I was able to get the fully qualified URL of this method GetStates() as follows:
// Get the fully qualifed URL of the FollowUpOptions() method for use in building the cascading dropdown
UrlHelper Url = new UrlHelper(System.Web.HttpContext.Current.Request.RequestContext);
myModel.ullDropdownUrl = Url.Action("GetStates", "Forms", new { }, this.Request.Url.Scheme);
Then I was able to do this in the javascript, which FINALLY got it all working:
url: '#Model.fullDropdownUrl'

How do I append more data to an AngularJS model?

So far I'm having no issue setting up an AngularJS model in my Rails application and giving it data to access on the front-end. I even set it up to be populated with data from an AJAX request using $http. However, I need this this model to contain the data of multiple $http calls. Here's the code I've got thus far:
function DropboxCtrl($scope, $http) {
var $infiniteLoader = $(".infiniteLoader");
var theUIDS = $infiniteLoader.attr('data-dropbox-uids').split(',');
if($infiniteLoader.attr('data-dropbox-uids') != "") {
var theData = {};
$.each(theUIDS, function(key) {
$http({ url: '/dropbox/files/get', method: 'GET', params: { uid: theUIDS[key] }}).success(function(data) {
theData = data;
});
});
$scope.dropboxes = theData;
}
}
I have a method called DropboxCtrl which will start by getting all the UID's that I need to call a GET request on. I loop through each of them and then append data to theData which is a Javascript object. After the each I make my dropboxes model equal to the value of theData. Current I've got the method returning absolutely nothing and no Javascript errors. I am positive that my url works completely and actually did get the code working with just one AJAX request like such:
$.each(theUIDS, function(key) {
$http({ url: '/dropbox/files/get', method: 'GET', params: { uid: theUIDS[key] }}).success(function(data) {
$scope.dropboxes = data;
});
});
However... that code block only returns the last AJAX call because the other ones are overwritten. Maybe what I'm missing is just incorrect Javascript, however, maybe what I'm missing is just a lack of understanding the "Angular way" of things. I'm skilled in Javascript and jQuery, but very new to Angular. Any help?
AngularJs is a high level Javascript framework. The code ultimately is javascript. Within your $each, you can push results to an array or to an initialized collection like
$scope.dropboxes = [{uid:1234}, {uid:2345}] and so on.
within the $each, locate the record for uid and attach the results.
I usually use underscorejs library for operations on collections, arrays etc.
so something like
_.findWhere($scope.dropboxes, {uid: data.uid }).data = data;
assuming the data that is returned has uid in it. If not then there should be another way to map the results to the request. Note that there is no guarantee of the order of responses, so you cannot use array indexes to map results.

Rendering mongodb database results from POST request in .ajax jquery wrapper in node js

I am creating a basic piece of functionality to allow users to send their location to a server which then queries a database and returns locations near to them. I am using the below jQuery .ajax wrapper to POST data to the server. This takes the form of a latlon point which is then used as the basis for a geosearch in MongoDB using nodejs and express on the backend. The results of the search are then intended to be returned to the client and rendered by the createMapListings function.
The /find page is initially rendered through a GET request to the database via mongodb separate from the below code. However subsequent to initial rendering, I then want to return results dependent on the location provided.
The POST method works fine and the location is posted to the server, with the search results being returned as I can print contents out through the console log.
However, I then want to render the results on the client-side. As mentioned, the results of the search render in the console, but when I attempt to pass through to the client, I can render the data itself (in the form of an array of objects) in the #output div, but the createMapListings function does not seem to catch the data.
In fact, the below function appears to be called but prints out over a thousand rows with the data that should be caught described as 'undefined'. I have tried to use res.render and res.redirect, but in the first case, the view renders in the div (which I suppose is expected) and the redirect fails.
The createMapListings function works fine when a simple GET request is made to the server, for example, for all objects in a collection, using ejs template. However, I think the issue here may be a combination of a POST request and then wanting to pass the results back to the AJAX request using the complete callback.
I apologise if the below code is somewhat obtuse. I’m definitely what you would call a beginner. I appreciate the above functionality may not possible so if there is a better way, I would of course be open to it (res.direct perhaps).
Here is the relevant client side script:
$(document).ready(function(){
$("#geolocate").click(function(){
navigator.geolocation.getCurrentPosition(geolocate, function(){
});
});
});
function geolocate(pos){
var latlonpt = [];
var x = pos.coords.latitude;
var y = pos.coords.longitude;
latlonpt.push(x);
latlonpt.push(y);
var obj = {
userlocation: latitudelongitudept
};
$.ajax({
url: "/find",
type: "POST",
contentType: "application/json",
processData: false,
data: JSON.stringify(obj),
complete: function (data) {
$('#output').html(data.responseText);
$('#infooutput').children().remove();
createMapListings(data.responseText);
}
});
};
function createMapListings(maps) {
for (var i = 0; i < maps.length; i++) {
var url = maps[i]._id;
var fullurl = "<a href='/show?id=" + url + "'>Route</a></div>";
var title = "<div>" + maps[i].title + " - " + fullurl +"";
$('#infooutput').append(title);
};
};
</script>
Here is the relevant route used in a basic express app to handle the post request made by the above .ajax wrapper.
exports.findbylocation = function(req, res) {
console.log(req.body.userlocation);
var userlocation = req.body.userlocation;
Map.ensureIndexes;
Map.find({loc :{ $near : userlocation }}, function(err, maps) {
if (err) {
console.log(err)
}
else {
var jmaps = JSON.stringify(maps);
console.log(jmaps);
res.send(jmaps);
}
});
};
By convention, the data variable name in an $.ajax callback signature refers to the parsed HTTP response body. Since your callback is on complete, we're actually passed the XMLHttpRequest used, by convention called xhr. You rightly grab the responseText property, but this needs parsing to be useful. So long as we take care over our Content-Type's and don't explicitly disable processData, jQuery will do the encoding/unencoding for us - we just deal with objects. This is a good thing, since the transport format isn't usually of any particular importance to the application logic. If we use res.json(maps) in place of res.send(jmaps), we can write our call more simply:
$.ajax({
url: '/find',
type: 'POST',
data: obj,
success: function(data) {},
error: function(xhr, text, err) {}
});
Here data is a Javascript object already parsed and ready to use. We also use a default application/x-www-form-urlencoded request rather than explicitly setting a contentType. This is the same as far as express is concerned: it will just be parsed by urlencoded instead of json.
Assuming you solved your client-sie problem.
As you are using express there is no need for JSON.stringfy,
you can use res.json(maps).

How to pass data from one HTML page to another HTML page using JQuery?

I have two HTML pages that work in a parent-child relationship in this way:
The first one has a button which does two things: First it requests data from the database via an AJAX call. Second it directs the user to the next page with the requested data, which will be handled by JavaScript to populate the second page.
I can already obtain the data via an ajax call and put it in a JSON array:
$.ajax({
type: "POST",
url: get_data_from_database_url,
async:false,
data: params,
success: function(json)
{
json_send_my_data(json);
}
});
function json_send_my_data(json)
{
//pass the json object to the other page and load it
}
I assume that on the second page, a "document ready" JavaScript function can easily handle the capture of the passed JSON object with all the data. The best way to test that it works is for me to use alert("My data: " + json.my_data.first_name); within the document ready function to see if the JSON object has been properly passed.
I simply don't know a trusted true way to do this. I have read the forums and I know the basics of using window.location.url to load the second page, but passing the data is another story altogether.
session cookie may solve your problem.
On the second page you can print directly within the cookies with Server-Script tag or site document.cookie
And in the following section converting Cookies in Json again
How about?
Warning: This will only work for single-page-templates, where each pseudo-page has it's own HTML document.
You can pass data between pages by using the $.mobile.changePage() function manually instead of letting jQuery Mobile call it for your links:
$(document).delegate('.ui-page', 'pageinit', function () {
$(this).find('a').bind('click', function () {
$.mobile.changePage(this.href, {
reloadPage : true,
type : 'post',
data : { myKey : 'myVal' }
});
return false;
});
});
Here is the documentation for this: http://jquerymobile.com/demos/1.1.1/docs/api/methods.html
You can simply store your data in a variable for the next page as well. This is possible because jQuery Mobile pages exist in the same DOM since they are brought into the DOM via AJAX. Here is an answer I posted about this not too long ago: jQuery Moblie: passing parameters and dynamically load the content of a page
Disclaimer: This is terrible, but here goes:
First, you will need this function (I coded this a while back). Details here: http://refactor.blog.com/2012/07/13/porting-javas-getparametermap-functionality-to-pure-javascript/
It converts request parameters to a json representation.
function getParameterMap () {
if (window.location.href.indexOf('?') === (-1)) {
return {};
}
var qparts = window.location.href.split('?')[1].split('&'),
qmap = {};
qparts.map(function (part) {
var kvPair = part.split('='),
key = decodeURIComponent(kvPair[0]),
value = kvPair[1];
//handle params that lack a value: e.g. &delayed=
qmap[key] = (!value) ? '' : decodeURIComponent(value);
});
return qmap;
}
Next, inside your success handler function:
success: function(json) {
//please really convert the server response to a json
//I don't see you instructing jQuery to do that yet!
//handleAs: 'json'
var qstring = '?';
for(key in json) {
qstring += '&' + key + '=' + json[key];
qstring = qstring.substr(1); //removing the first redundant &
}
var urlTarget = 'abc.html';
var urlTargetWithParams = urlTarget + qstring;
//will go to abc.html?key1=value1&key2=value2&key2=value2...
window.location.href = urlTargetWithParams;
}
On the next page, call getParameterMap.
var jsonRebuilt = getParameterMap();
//use jsonRebuilt
Hope this helps (some extra statements are there to make things very obvious). (And remember, this is most likely a wrong way of doing it, as people have pointed out).
Here is my post about communicating between two html pages, it is pure javascript and it uses cookies:
Javascript communication between browser tabs/windows
you could reuse the code there to send messages from one page to another.
The code uses polling to get the data, you could set the polling time for your needs.
You have two options I think.
1) Use cookies - But they have size limitations.
2) Use HTML5 web storage.
The next most secure, reliable and feasible way is to use server side code.

Categories

Resources