Knockoutjs elegant way of populating the observable properties after posting to server - javascript

I just wanted to know, what is the elegant way of populating the observable properties after posting json to the server.
my js
var vm = (function() {
var commit = function(item) {
var model = {
Name: item.name(),
IsActive: item.is_active()
};
$.post('/to/server/Post', model);
.done(function(d) {
item.id(d.Id);
});
}
}());
in my server
public JsonResult Post(itemVm model)
{
var item = new Item
{
Name = model.Name,
IsActive = model.IsActive
};
// do saving here and commit to database
model.id = item.Id;
return Json(model, JsonResultBehavior.DenyGet);
}
While above snippet will work. I find it hard to maintain it this way, is there an elegant or another way of doing this? I need the returned Id for update later on.
Btw, I'm using ASP.NET MVC 5, KnockoutJs
Any help would be much appreciated. Thanks

Related

passing an object from javascript to controller through jquery post function (web API)

in my application I have my JS file that reads some info filled in the html page. What I want to do now I passing these info to my controller. So in my script I have:
function addNewEmployee() {
var newEmployeeName = document.getElementById("newEmployeeName").value;
var newEmployeeSurname = document.getElementById("newEmployeeSurname").value;
var newEmployeeDateOfBirth = document.getElementById("newEmployeeDateOfBirth").value;
var newEmployeeRole = document.getElementById("newEmployeeRole").value;
var newEmployeeEmail = document.getElementById("newEmployeeEmail").value;
var newEmployee = {
name : newEmployeeName,
surname: newEmployeeSurname,
dateOfBirth: newEmployeeDateOfBirth,
role: newEmployeeRole,
email : newEmployeeEmail
}
$.post("api/addemployees", {'newEmployee': newEmployee}, function(result) {
});
}
I would like to know if passing an object in this way is correct and then how can I receive it on my controller side:
[HttpPost]
[Route("api/addemployees")]
public bool AddEmployee (Object newEmployee)
{
return true;
}
Unfortunately by debugging on the controller side I realized that this way is not correct because nothing arrives. How can I solve this? Thanks in advance.
Just pass the object like
$.post("api/addemployees", JSON.stringify(newEmployee), function(){
})

Retrieving items from ViewModel with a linq where clause that needs a JavaScript variable as a parameter

I have an Index.cshtml razor view that lists NewsFeedPosts on it.
In the controller when in the Index() Action Method I am calling my repository initially getting all of the NewsFeedPosts along with their Comments like this:
var newsFeedPosts = _context.NewsFeedPosts
.Include(p => p.Comments)
.OrderBy(t => t.CreatedDate)
.ToList();
In the actual view I am doing something like this to only show the first 4:
<div id="comments">
#foreach (var comment in post.Comments.Take(4))
{
...
}
</div>
Then I will have a link that says 'View additional comments', kind of like how StackOverflow does it.
On Click of this link:
I know I can get this does with an Ajax request calling an action Method called GetNewsFeedPostComments and simply loop through them and append to the #comments div.
However, since I am already retrieving all of the Comments on page load (as shown in the below code) is this really the best way to do this? I feel like there is a better way since I already have all Comments for each news feed post inside of my ViewModel already.
Here is what my pages ViewModel looks like:
public class NewsFeedPostIndexViewModel
{
public IEnumerable<NewsFeedPostViewModel> NewsFeedPosts { get; set; }
}
and when the page initially loads here is how I am populating this ViewModel and sending it to the View:
// GET: NewsFeedPosts
public IActionResult Index()
{
// Get a list of all NewsFeedPosts including comments
var newsFeedPosts = _repository.GetAllNewsFeedPosts();
var newsFeedPostViewModels = newsFeedPosts.Select(fp => new NewsFeedPostViewModel()
{
Id = fp.Id,
Title = fp.Title,
Content = WebUtility.HtmlDecode(fp.Content),
Comments = fp.Comments
}).ToList();
NewsFeedPostIndexViewModel vm = new NewsFeedPostIndexViewModel()
{
NewsFeedPosts = newsFeedPostViewModels
};
return View(vm);
}
So in this JavaScript function is there anyway to utilize what I already have bound in the ViewModel?
$(".lnkViewAdditionalComments").click(function (e) {
e.preventDefault(e);
var newsFeedPostId = $(this).attr('data-newsFeedPost-Id');
// retrieve remaining comments by using skip(4) and loop through them
var comments = #Html.Raw(Model.NewsFeedPostIndexViewModel.Where(f => f.Id = // need to pass JS string here: feedPostId)));
// foreach $(#comments).append(".....");
});
why don't you use grep function in Js
#{
var GetAllComments = Model.FeedPosts.Select(x => x.Comments);
}
<script>
var feedPostId = 1;
var GetCommentJs =#(Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(GetAllComments)));
var filterFata = $.grep(GetCommentJs, function (value, index) {
return value.FeedPostId == feedPostId;
});
</script>
NOTE: you can use also slice function to take limited number of
records after grep.

Knockout mapping data from server, lost subscriptions

I'm trying to represent multiple selects with its selected values from backend JSON to knockout view model.
And it's needed to retrieve this JSON when each select is changed, first time - all is ok, but if I apply mapping again (ko.mapping.fromJS(test_data, ViewModel)), all subscriptions are lost does anyone know how to avoid this situation?
jsfiddle (I don't know why selects don't have its values, without jsfiddle - all is ok):
http://jsfiddle.net/0bww2apv/2/
$(ViewModel.attributes()).each(function(index, attribute) {
attribute.attribute_value.subscribe(function(name) {
console.log('SUBSCRIBE', name);
var send_data = {};
$(ViewModel.attributes()).each(function (index, attribute) {
send_data[attribute.attribute_name.peek()] = attribute.attribute_value.peek();
if (attribute.attribute_value() === null) {
send_data = null;
return false;
}
});
if (send_data) {
console.log('REQUEST TO BACKEND: ', ko.toJSON(send_data));
ko.mapping.fromJS(test_data, ViewModel);
// subscriptions is lost here !
}
});
});
At last I've solved my own question with knockout.reactor plugin,
If we remove all auxiliary constructions, it will look like:
var ViewModel = ko.mapping.fromJS(test_data);
ko.applyBindings(ViewModel);
ko.watch(ViewModel, { depth: -1 }, function(parents, child, item) {
// here we need to filter watches and update only when needed, see jsfiddle
ko.mapping.fromJS(test_data2, {}, ViewModel);
});
This way we update selects and don't have troubles with subscription recursions.
full version (see console output for details): http://jsfiddle.net/r7Lo7502/

unable to add parsed JSON to backbone collection

I am trying to parse a multilevel json file, create a model and then add that model to a backbone collection but i can't seem to figure out how to push the model to the collection. This should be a pretty easy problem to solve, i just can't seem to figure it out. Thanks in advance for your help. Below is my model and collection code:
var Performer = Backbone.Model.extend({
defaults: {
name: null,
top5 : [],
bottom5 : []
},
initialize: function(){
console.log("==> NEW Performer");
// you can add event handlers here...
}
});
var Performers = Backbone.Collection.extend({
url:'../json_samples/performers.json',
model:Performer,
parse : function(data) {
// 'data' contains the raw JSON object
console.log("performer collection - "+data.response.success);
if(data.response.success)
{
_.each(data.result.performers, function(item,key,list){
console.log("running for "+key);
var tmpObject = {};
tmpObject.name = key;
tmpObject.top5 = item.top5;
tmpObject.bottom5 = item.bottom5;
var tmpModel = new Performer(tmpObject);
this.models.push(tmpModel);
});
}
else
{
console.log("Failed to load performers");
}
}
});
As has been said in comments to your question, parse() is not intended to be used this way. If data.results.performers was an Array, all you would have to do is returning it. In your case the code will be slightly different.
var Performers = Backbone.Collection.extend({
...
parse: function(resp, options) {
return _.map(resp.result.performers, function(item, key) {
return _.extend(item, {name: key});
});
}
...
});
On the advice side, if you have the chance to change the API server-side, you'd probably be better off treating collections of objects as arrays and not as objects. Even if it is sometimes convenient to access an object by some ad-hoc key, the data really is an array.
You'll be able to transform it later when you need performers-by-name with a function like underscore's IndexBy

Retrieving Specific Data From JSON Using a Backbone Model

I am creating a client view of an application and I need help with retrieving specific data from my JSON file. I am using Backbone.js along with Underscore.js to achieve this.
(function($) {
window.Node = Backbone.Model.extend({
getName: function(){
return this.get('Name');
}
});
window.Nodes = Backbone.Collection.extend({
model:Node,
url: '/packageview.json'
});
window.NodeView = Backbone.View.extend({
tagName: "div",
className: "package-template",
events:{
"click #display-name" : "displayname",
},
//.. I have a render and initialize function here which should not be a concern
displayname: function(){
var node = new Node();
alert(node.getName()); //trying to alert
},
});
});
I am trying to get the name from model and alert it. I have a button in my html with an id, and when I press that button I get "undefined" as an alert. Here is how my JSON file looks:
{
"Id": 2,
"Name": "Some Package",
"IsComplete": false,
"IsNodeTagComplete": false
}
I think I am making a silly mistake somewhere. Am I expecting way to much from model?
What I am doing here is this
window.jsonAccess = Node.extend({ // Here Node is my above mentioned model
getJSON: function(){
var collection = nodeInstance.toJSON(); // nodeInstance is an instance of my collection Nodes
return collection; //returns JSON
}
});
jAccess = new jsonAccess();
So here is what I am doing to access the JSON
getNodeId: function(){ //Function to get Node Id from JSON
objectJSON = jAccess.getJSON(); // Get JSON
_.each(objectJSON, function(action){
_.each(action.Nodes, function(action){
This solves my purpose but not quite the way getters would be used in backbone.
Since a lot of context is missing I too may be making a mistake but here's my guess - you are creating an empty Node Model. Try doing something like this in display:
displayName: function() {
var myJSON = window.getJSONObject(); //wherever your json object is or how to get it...
var node = new Node({
id:myJSON.Id,
name:myJSON.Name,
isComplete: myJSON.IsComplete,
...
});
alert(node.get('name'));
alert("Getter: "+node.getName()); //your version...
}
This is just a hunch though...maybe I'm missing your context but this seems to be the case for now...

Categories