In Laravel, I have an Eloquent Model Person and a function getSomestringFromPerson() which is operating on the Model Person and returning a string. Now I have an AJAX request whose response is a collection of Persons. Until here I know what to do.
Now, in the JavaScript I would like do display the result of getSomestringFromPerson() for each Person in the response.
Is that possible? If yes, how? Or do I have to run the function in the Controller and include the result in the AJAX response? (That looks a bit cumbersome to me...)
In the controller that handles the AJAX request, I assume it gets a collection of People like something like this (at a bare minimum):
public function handleAjax(Request $request){
$people = People::get();
return response()->json(["people" => $people], 200);
}
And then in your JS a function for handling the response:
$.get(URL, function(data){
console.log(data); // Collection (js object) of `People` models.
});
In your handleAjax function, you would loop over each of your People and assign a property to hold the value of $person->getSomestringFromPerson():
foreach($people AS $person){
$person->someString = $person->getSomestringFromPerson();
}
Then, in your Javascript code, you would be able to access it like so:
for(var person in data.people){
console.log(data.people[person].someString); // Should return the expected value of `$person->getSomestringFromPerson();` as defined in your function.
}
From there, you should be able to do whatever else it is you'd need to do with your data.people object.
Related
Hi , I have some issue with parse method!!!!!
as you can see in backbone js document the parse method in collection has this syntax :
collection.parse(response, options)
1) I want to know why we should use / override the parse method and what is the main usage of that?
2) I read some article and I get that the parse method give us the data structure for the client-side.
3 ) I really have issue for understanding the arguments of parse method .
- what is the options for??
can you give me an example of using parse method with two parameters?
Thanks!
The docs have a nice summary:
parse is called by Backbone whenever a collection's models are returned by the server, in fetch. The function is passed the raw response object, and should return the array of model attributes to be added to the collection. The default implementation is a no-op, simply passing through the JSON response.
http://backbonejs.org/#Collection-parse
1) You should return an array of model attributes. If your JSON response only has this then you don't need to do anything. Typically the parse override is used simply to point inside the JSON object at the right part. For example if your response was like this:
{
httpCode: 200,
responseMessage: 'success',
data: [ {model1}, {model2} ...]
}
Then you would need to override parse to point to the data key:
parse: function(response) {
return response.data;
}
2) They meant that the response arg is the object which was returned by the server.
3) The second options arg is the options that was passed to the .fetch call. You don't need to worry about it unless you want to do some specific logic based on the URL, the HTTP method or anything else that can be passed to fetch (and jQuery.ajax options and some Backbone ones like reset).
4)
parse: function(response, options) {
// For some reason POST requests return a different data structure.
if (options.method === 'POST') {
return response.data;
}
return response;
}
I have a simple model called BaseModel that extends from a Backbone.Model. According to Backbone.js documentation I've overridden parse method to work with a preexisting API.
The parse method is called in two different situation. When from a collection I want to fetch to grab all data. When from a model I want to fetch a specific data.
Within BaseModel to differentiate the behavior I'm doing the following.
parse : function(response, options) {
var result;
if(options.collection) {
// I'm coming from the fetch that belongs to the collection
// manipulate result here...
} else {
// I'm coming from the fetch that belongs to the model
// manipulate result here...
}
return result;
}
Is this appraoch valid or is there a better way to achieve this?
Edit 1
I thought on Andrew answer but the situation I need to manage is weird. In fact, when the parse method is called the first time (from the collection) data are parsed and properties for the model are created. Then, when the parse method is called from the model itself, additional data are parsed and properties for the model are merged to the first ones.
Edit 2
In my situation, for example, response coming from collection contains an array of objects where each object has a property a. Conversion can be applied, e.g. date obj. Then, response coming from model contains b. Also here conversion can be applied. At the end both properties will be merged into the same model but they are coming from different fetch calls.
Notice that response in collection is already an array. So, I do not to differentiate or split nothing here. I would just know that if I come from collection, I will find a, b otherwise.
Read the fetch in the collection as give me all models, while the other call as based on a model returned from the collection, enrich it by details.
Backbone.Collection also has a parse method. In my opinion the correct way is to implement it for both your BaseModel and your Collection.
The collections parse method only needs convert the data to be an array of unparsed models. It then delegates to the BaseModel parse method automatically to parse each one individually.
e.g.,
BaseModel {
parse : function(response, options) {
var result;
// I'm coming from the fetch that belongs to the model
// manipulate result here...
return result;
}
}
BaseCollection {
parse : function(response, options){
// I'm coming from the fetch that belongs to the collection
// Turn it into an array.
return response.split('mydelim');
}
}
From your edit 2, It looks like your approach is the right idea. I would however say that if I where to do it, I would test the returned object for properties rather than the context of the call so I don't need to care about the datasource,
parse : function(response, options) {
var result = {};
if(response.a){
result.c = response.a;
} else if(response.b){
result.c = response.b;
}
...
return result;
}
First off, some background
My client has a kind of a "split-view", meaning- a side-panel displaying a list of objects and a main view displaying the selected object's details. Every time the user clicks on an Object in the list, a Backbone's route is called to navigate to the id which updates a "selected" property on the Session, what causes the main view to update- pretty standard stuff.
The problem
I want the client to be as responsive as possible, therefore i'm trying to utilize Meteor's abillity to update the client immediately without waiting for a server confirmation.
My goal is that every time an Object is created, the list and the main view will be instantly updated to reflect the newly added Object. To achieve this I created a Meteor.method, create(), that uses Collection.insert and returns the id so I can use it with my Route. The method is shared across the client and server and is being called from within a template's event handler.
My first try was to store the returned id in a variable in the event handler and update the Route in the next line; For some reason, that didn't work because the method returned an undefined value. So I tried a different approach, instead of returning the id, I used it within the method to update the Route directly (if Meteor.isClient of course). That didn't work either because the id returned by Collection.insert in the client's version of the method was different from the one in the server's version.
First approach
Template.createDialog.events({
'click #btn-dialog-create': function (event, template) {
var objectId = Meteor.call('create');
appRouter.navigate("object/id/" + objectId, {trigger:true});
}
});
Second approach
Meteor.methods({
create: function () {
var ObjectId = Objects.insert({name:'test'});
if(Meteor.isClient){
appRouter.navigate("object/id/" + objectId, {trigger:true});
}
}
});
If anyone knows what's going on and can give me some directions that would be great.
Any different approaches to the problem or suggestions would be much appreciated as well.
Thanks
Update
So I tried #Pent's suggestion and I got the same result as with my second approach. For some odd reason Meteor decides to ignore my id (created with Random.id()) and inserts the object with a different one.
So I tried another approach, I used just a simple string value instead of Random.id() and voila - it worked. Riddle me that.
Answer updated:
This will be both a client and server method:
Meteor.methods({
create: function () {
var id = Random.id();
Objects.insert({_id: id, name:'test'});
if(this.isSimulation) {
appRouter.navigate("object/id/" + id, {trigger:true});
}
}
});
You can view a similar pattern from Meteor's party example: https://github.com/meteor/meteor/blob/b28c81724101f84547c6c6b9c203353f2e05fbb7/examples/parties/model.js#L56
Your problem is coused by the fact that remote methods, i.e. those which will be called on the server, don't simply return any value. Instead, they accept a callback that will be used to process the returned value (see docs). So in your first example you should probably do something like this:
Template.createDialog.events({
'click #btn-dialog-create': function (event, template) {
Meteor.call('create', function (error, result) {
if (!error)
appRouter.navigate("object/id/" + result, {trigger:true});
});
}
});
You also said:
I want the client to be as responsive as possible, therefore i'm trying to utilize Meteor's abillity to update the client immediately without waiting for a server confirmation.
I think that in this case you should definitely wait for server response. Note, that there is no chance you get the correct object id unless this is given to you by the server.
One possible way to get around this issue is to create a local (client-side) collection:
// only on client
var temporary = new Meteor.Collection(null); // null name
in which you could store your "temporary" newly created objects, and then save them to the "real" collection after the user clicks the save button. You could implement your router to respond to urls like object/new/* to get access to these objects before they're saved to your database.
The correct answer for this question is defining a client side method that's responsible for creating the unique id (preferably using Random.id() ) and calling the Meteor.methods' create(). That way, you can have the id available immediately without waiting for the server to generate one. The trick here is to generate the id outside of the Meteor.method so that the id generation happens only once for both the stub and the actual server method.
create = function(){
var id = Random.id();
Meteor.call('create', id);
return id;
}
Meteor.methods({
create: function (id) {
Objects.insert({_id: id, name:'test'});
//more code...
}
});
//and in the Template...
Template.createDialog.events({
'click #btn-dialog-create': function (event, template) {
var objectId = create();
appRouter.navigate("object/id/" + objectId, {trigger:true});
}
});
In my controller, I send an object list into the view (index.cshtml)
return View(AdsPrevModel);
in my index.cshtml:
<div id ="ele">
<ul>
<li> name1<input id="a1" type="checkbox"/></li>
</ul>
</div>
when the user clicks the checkbox, I use jquery to know if the user checked the box or not:
My javascript file:
$('#ele :checkbox').click(function () {
if ($(this).is(':checked')) {
alert($(this).attr('id'));
} else {
alert('unchecked');
}
});
How can I get my AdsPrevModel into my js file?
I know I can do something like this:
In my html, add:
<input type="hidden" id="AdsPrevModel" value="#Model.AdsPrevModel" />
and in the js:
var adsPrevModel = JSON.parse(document.getElementById('AdsPrevModel').value);
Is there another option without adding a hidden input in my html?
Maybe something like the following in the js file:
var adsPrevModel = JSON.parse(Model.AdsPrevModel));
The best practise is
do an ajax call to that controller and that controller should return json results
return JSON( model ) ;
In the code you've shared there's nothing emitting the model to the client, so there's currently no direct way for the JavaScript code to access it.
Since you're binding the view to the model, the view can include it in various ways. It could be a series of hidden fields for the members of the model (not the model in its entirety, unless it can be represented as a string in its entirety). Something like this:
#Html.HiddenFor(x => x.SomeField)
#Html.HiddenFor(x => x.AnotherField)
This would create two hidden inputs for two fields on the model. Depending on how complex the model is, this could get cumbersome.
You might also emit the model to the JavaScript code directly in a similar fashion:
var someField = #Model.SomeField;
var anotherField = #Model.AnotherField;
Again, if the model is complex, this gets cumbersome quickly. Even if you try to build an actual JavaScript object from it:
var theModel = {
someField : #Model.SomeField,
anotherField : #Model.AnotherField
};
(Note also that I've seen Visual Studio get very confused when you mix razor syntax and JavaScript like this. Not so much in 2012 anymore, but a lot in 2010.)
You might use something like the JavaScriptSerializer to add a property on the model for a serialized version of itself. I've never done this before, but it should work. Something like this on the model:
public string SerializedCopy
{
get
{
return new JavaScriptSerializer().Serialize(this);
}
}
It might take some tweaking to get it to work, though.
Finally, a particularly clean option which only requires another request to the server would be to have another action which just returns the JSON version of that model. Something like this:
public ActionResult SomeActionName()
{
// get the model somehow, then...
return Json(AdsPrevModel);
}
Your JavaScript code would then just need to call this action to get the JSON object representing the whole model:
var theModel = {};
$.get('#Url.Action("SomeActionName", "SomeController")', function (data) {
// maybe do some error checking here?
theModel = data;
});
Then if your actual view isn't actually binding anything to the model then the action which returns that view doesn't need to fetch the model and supply it to the view. The JavaScript code would get the model by calling this other action which returns JSON data instead of a view.
I've got a wcf service that returns me an array of items.
I've got a javascript method that recieves the items and handles them.
I want to send the javascript function another parameter from the client side, an id of an object on the page.
Something like this:
function WriteSonCategories(selectedCategoryId, callback) {
var d = new Date();
MyServices.GetSonCategories(selectedCategoryId,
d.getTime().toString(), callback );
}
I'd like the callback to be able to recieves a certain id, not just the array of objects returned from the service. How can this be achived?
Thank you!
Maybe Something like this.