It seems like at the moment when I call get on a backbone.js collection, it passes the id by cookie rather than restfully passing into my GET method. In the Request Header it's coming up like this:
Cookie:posts=ag5kZXZ-c29jcmVuY2h1c3IOCxIIUG9zdExpc3QYAQw;
dev_appserver_login="test100#example.com:False:114323764255192059842"
This is what I have:
The get call:
postCollection.get(id)
and the get method:
def get(self, id):
I want to use the id in the get method rather than having to use the cookie.
Probably the best way to accomplish this is something like the following.
var model = collection.get(id);
// If the model is not present locally..
if (!model) {
// Add empty model with id.
model = collection.add([{id: id}]);
// Populate model attributes from server.
model.fetch({success: successCallback, error: errorCallback });
}
collection.get(id) shouldn't be making a request to the backend.
Here's another take on it. Rather than creating a mostly empty model and then adding attributes to it from the server after fetch, you could do what i pasted below. One thing to think about with the above example, if you create a model and then try to fetch that ID from the server and it doesn't exist, you'll have to clean it up. The code below will save you that step.
myModel = Backbone.Model.extend({
url : function() {
/*
create _ POST /model
read _ GET /model[/id]
update _ PUT /model/id
delete _ DELETE /model/id
*/
return this.id ? '/model/' + this.id : '/model';
},
});
myCollection = Backbone.Collection.extend({
model: myModel,
url: function() {
return '/model';
},
comparator: function(model) {
return model.get("foo");
},
getOrFetch: function(id) {
var model = this.get(id) || this.getByCid(id);
if (model) return model;
var url = this.url() +"/"+ id
return new this.model().fetch({url:url});
}
});
var mc = new myCollection(new myModel({foo:"bar"}));
mc.getOrFetch(1)
Related
I am working on an ASP.NET MVC app (ASP.NET NOT ASP.NET Core).
When a View is rendered, the user can click on some buttons on the page to collapse or show divs associated with each button. The div changes its class depending on whether it is collapsed or shown. I am using bootstrap attributes for this, and it works fine.
Now I have a "Save" button on the page. When the user clicks on this button, I need to retrieve the ids and classes of the divs, and pass them TO the Controller (in an array/collection/dictionary whatever).
Is there a way/method in ASP.NET to send to the Controller the attributes (ids, classes, etc) of the DOM elements on the client's browser ?
Thanks
If you want to send some attributes of DOM to Controller, I have a way.
HTML:
<div id="demo-1" class="chosendiv other-className" data-code ="abc">Lorem Ipsum</div>
<div id="demo-2" class="chosendiv other-className" data-code ="xyz">Lorem Ipsum</div>
<div id="demo-3" class="other-className" data-code ="mnt">Lorem Ipsum</div>
<button id="btn-save" onclick="Save()">SAVE</button>
Javascript
<script>
function Save(){
var cds = document.getElementsByClassName('chosendiv');
var finder = [];
if(cds != null){
for(i = 0; i< cds.length; i++){
finder.push({
ID: cds[i].getAttribute('id'),
ClassName: cds[i].getAttribute('class'),
Code: cds[i].getAttribute('data-code')
})
}
}
//
// Send finder to Controller. You can use Ajax...
// A simple ajax call:
//
$.ajax({
url: '/Home/YourAction',
type: 'GET', //<---- you can use POST method.
data:{
myDiv: JSON.stringify(finder)
},
success: function(response){
// Your code
}
})
}
</script>
Your Controller
public class HomeController: Controller
{
public HomeController(){}
[HttpGet]
public void YourAction(string myDiv)
{
//A lot of ways for converting string to Object, such as: creating new class for model, ...
// I use Dictionary Class
List<Dictionary<string, string>> temp = new List<Dictionary<string, string>>();
if(!string.IsNullOrEmpty(myDiv))
{
try
{
temp = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(myDiv);
}
catch { // Do something if it catches error. }
}
// Get a element (at index) from temp if temp.Count()>0
// var id = temp.ElementAt(index)["ID"];
// var className = temp.ElementAt(index)["ClassName"];
// var code = temp.ElementAt(index)["Code"];
//
//Your code
//
}
//......
}
It would be great if my answer could solve your problem.
Based on the answer provided by #Gia Khang
I made few changes in order to avoid the issue of the length of the URL exceeding the maximum limit.
Instead of adding the element's classes to an array using JS, I add them to a string :
function Save() {
var cds = document.getElementsByClassName('chosendiv');
// I use as string instead of an array
var finder = "";
if(cds != null){
for(i = 0; i< cds.length; i++){
finder = finder + "id=" + cds[i].getAttribute('id') + "class=" + cds[i].getAttribute('class') + "data-code=" +cds[i].getAttribute('data-code')
}
}
// Send finder to Controller. You can use Ajax...
// A simple ajax call:
var myURL = "/{Controller}/{Action}"
$.ajax({
url: myURL,
type: "POST",
data: { ids:finder },
success: function (response) {
}
})
}
In the Controller Action I add a parameter named "ids" (this must be the same name as the identifier of the data object in the post request)and I extract the id, class, and data value from the ids string by a method in one of my Models classes (sorry I work with VB.NET not with C# and it will take me a lot of time to convert the code to C#. I use the Split method in VB to split the ids string several times: a first one by using "id=" as delimiter, then spiting each element in the resulting array by the second delimiter "class=", etc. I add the resulting elements to a collection)
The Controller Action looks like this:
public class HomeController: Controller
{
public HomeController(){}
[HttpPost]
public void YourAction(string ids)
{
Models.myClass.splitStringMethod(ids)
Return View()
}
}
I have an array of integers called data which I would like to send from my View to a specific controller, I could see that i can send integers and strings and it works with the code that I have so far, but when I try to send an array I can get the data correctly.
This is the code that I have in my view, it is something simple just to be in perspective.
function SeeStation() {
var data = [];
var i = 0;
$("input:checkbox:checked").each(function () {
data[i] = $(this).val();
});
window.location.href = "#Url.Action("ExportData", "Dispatch")?id=" + data;
}
and this is the code in the controller. I know it doesn't make much sense but so far I am focused on correctly obtaining the array by parameter.
public ActionResult ExportData(int[] id)
{
var data = cn.ESTACIONDESPACHOes.ToList();
return View(data);
}
In my array data I store something like this [1,2,3] and I would like to get something similar in the controller array id.
It will not bind like that.
To get the id array in your action you need to have the link at the end like this: *Dispatch/ExportData?id=1&id=2&id=3*
Your "#Url.Action("ExportData", "Dispatch")?id=" + data; will not generate that (data will give the numbers separated with commas).
You can just build the query string when you enumerate the checkboxes.
function SeeStation() {
var data = '';
$("input:checkbox:checked").each(function () {
data += 'id='$(this).val() + '&';
});
window.location.href = "#Url.Action("ExportData", "Dispatch")?" + data;
}
You will have a "&" in the end. You can easily remove it, but it will not affect anything.
There may be better ways to do this though, but I just used your function.
try
#Url.Action("ExportData", "Dispatch", new { id= [1,2,3] })
Store the Values in the Hidden Fields
#Html.HiddenFor(m => m.Ids, new { #Value = [1,2,3] })
Then Using the Ajax Get Method Pass the Hidden fields
In the Controller Method Convert the sting to array using string extension method
function SeeStation() {
var data = [];
var i = 0;
$("input:checkbox:checked").each(function () {
data[i] = $(this).val();
});
location.href = '#Url.Action("ExportData", "Dispatch")?id=' + data;
}
Please remove window keyword.
Hi guys looking for some basic advice.
I have four models: BoardViewModel, List, Card, Member
var Member = function (id, name, avatar) {
var self = this;
self.id = id;
self.name = name;
self.avatar = avatar;
self.isChecked = ko.observable(false);
};
I am instantiating members property inside BoardViewModel. But I want to use a copy of this model inside each Card model to instantiate a list of assigned members.
Each card stores comma separated list of member references like
",1,2,4,5"
I am writing a loop to BoardViewModel.members and mark members as checked if id references match bore I assign it as Card.members.
The last piece of the puzzle I am missing is reference to the BoardViwModel.members.
I have a lovely example fiddler that would somewhat help to build a picture of what I am talking about.
Just bear in mind that once I have this working properly I want to replace view() binding
foreach: $root.members
with
foreach: members
If at all possible I would like to avoid passing BoardViewModel.members as parameter into List and then into Card.
Update 1
As suggested by #Jeroen here's a simplified version of my fiddler.
The top view() model which encompases a concept of lists:
var BoardViewModel = function (lists, members) {
var self = this;
// in reality members are fetched via ajax call to the server
// and instantiate as a ko.observableArray()
self.groupMembers = ko.observableArray(members);
self.lists = ko.observableArray(lists);
...
}
In reality this has a signature like this:
var boardViewModel = function (initialData)
moving on.
The child List model which encompases a concept of cards:
var List = function (id, name, cards, sortOrder, groupMembers) {
var self = this;
self.cards = ko.observableArray(cards);
...
}
in reality:
var list = function (item, groupMembers)
nothing special there really.
The child Card model which encompases the concept of card items (but lets not go there yet):
var Card = function (id, title, description, contentItemId, members, groupMembers) {
var self = this;
self.members = ko.observableArray(parseMembers(members));
// now remember each card has a members property
// which stores comma separated list ",1,4"
function (members) {
var memberList = groupMembers;
var memberRefList = members.split(',');
ko.utils.arrayForEach(memberList, function(member){
ko.utils.arrayForEach(memberRefList, function(memberId){
if(member.id === meberId) {
member.isChecked(true);
}
});
});
return memberList;
}
...
}
in reality:
var card = function (item, groupMembers)
nothing too fancy there either.
I currently have something like this working on my dev environment.
Problem:
Those with keen eyes probably noticed the way I was passing groupMembers all the way up. I am not particularly hyped about the idea.
Anyone know a better way of implementing this? i.e. why can't I just do something like
var memberList = self.parent.parent.groupMembers;
for instance.
As per me, the better way to do is to have the child viewmodels inside the parent view-model. like this where you can access the parent data members as well as methods directly.
ViewModel
var BoardViewModel = function(){
var self = this;
this.members = ko.observableArray();
this.lists = ko.observableArray();
// Child View Models
this.Member = function(member){
this.id = member.id;
this.name = member.name;
this.avatar = member.avatar;
this.isChecked = ko.observable(false);
}
this.List = function(list){
// same for this
};
this.Card = function(card){
// same for this
};
// a Method to bind the data with the observables and arrays
// Assuming data is a json object having Members, List objects
this.applyData = function(data){
self.members(jQuery.map(data.Members, function(item){
return new self.Member(item);
}));
self.lists(jQuery.map(data.Lists, function(item){
return new self.List(item);
}));
}
}
onDom ready
// json object holding your data
var data = {
"Members" : [
],
"Lists" : [
],
"Cards" : [
]
};
var vm = new BoardViewModel();
$(function(){
ko.applyBindings(vm, document.getElementById('myModule'));
vm.applyData(data);
});
I have a view form that contains a table with textfield inside it.
I need to save the information of the table inside a database.
* javascript function *
function sendTableToServer()
{
var table;
table = document.getElementById('myTable');
var rowLength = table.rows.length;
var tableArray = [rowLength -1];
var JSONObject;
for (var tblRow = 1; tblRow < rowLength; tblRow++){
console.log("***** ROW CHANGE *****");
JSONObject = {
"rowIndex": "myTableRow" + tblRow,
"partNo": table.rows[tblRow].cells[0].firstChild.value,
"partName":table.rows[tblRow].cells[1].firstChild.value,
};
f24Array[tblRow] = JSONObject;
}
console.log(f24Array[rowLength-1]["rowIndex"]);
console.log(f24Array.length -1);
$.getJSON("f24BatcCreateEAF.do", {
type: "F24",
pRefForm: "DVL",
pF24Values: tableArray
}
, function(ans) {
console.log("The row is" +ans.strVar);
}
);
};
* controller *
public #ResponseBody
AjaxReturnMessage createEaf( Model model, HttpServletRequest pRequest, #RequestParam String type, #RequestBody String[] pF24Values ) throws Exception {
long eafId=0;
AjaxReturnMessage pARM = new AjaxReturnMessage();
log.info( "entering creatEaf );
try {
System.out.println("calling gF24BatchService");
eafId = gF24BatchService.createEAFRow( model, pp, type, pRefForm, pDescription );
pARM.setId( eafId );
pARM.setStrVar( "f24TableRow1" );
pARM.setCode( AjaxReturnMessage.STATUS_ERROR );
} catch ( Exception e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// return the jsp page only
return pARM;
}
When i trigger the sendTableToServer function i get an error "404".
But if i remove the pF24Values from the JSON call and he service then there is no error.
How would it be possible for me to "catch" pF24Values without having to create a new object type. is this possible?
Thanks
You are performing a GET to your controller, so that controller can only capture data via request parameters. In addition, your getJSON function is sending all the data as request parameters as well.
Therefore your controller has to capture pF24Values as a #RequestParam, not as a #RequestBody.
If you want to send complex data structures to your controller you need to do a POST with the JSON as the request body (for instance) - although you can use GET for array data but not the way you are doing it here - each row needs to have a separate request param(e.g. pF24Values:one and pF24Values:two, etc - there are a few ways to do this).
I am working on an ASP.Net MVC app and I want to show a confirmation page after the user edits some data. What I would like to show is a list of the pending changes that the user made to the model.
For example,
Are you sure you want to make the following changes:
FieldName:
Previous Value: XXX
New Value: YYY
I know I can read my stored value from the database and compare it with the POSTed object but I want this to work generally. What would be some good ways to approach this?
To clarify, I am looking for a general way to get a "diff" of the pending changes. I already know how to get the previous and pending changes. Kind of like how TryUpdateModel() can attempt to update any Model with posted values. I'd like a magical GetPendingModelChanges() method that can return a list of something like new PendingChange { Original = "XXX", NewValue = "YYY"} objects.
You might be doing this already but I wouldn't send my model to the view, create a viewmodel. In this case I would map the model data to the viewmodel twice, my viewmodel might contain OrderInput and OrderInputOrig. Then stick OrderInputOrig in hidden fields. On post back you can compare the values and then redirect, if something changed, to a display view with the original and the changes for confirmation.
Maybe something like this:
[HttpPost]
public ActionResult Edit(CustomerInput cutomerInput)
{
var changes = PublicInstancePropertiesEqual(cutomerInput.OriginalCustomer, cutomerInput.Customer);
if (changes != null)
{
cutomerInput.WhatChangeds = changes;
return View("ConfirmChanges", cutomerInput);
}
return View();
}
public ActionResult ConfirmChanges(CustomerInput customerInput)
{
return View(customerInput);
}
from: Comparing object properties in c#
public static Dictionary<string, WhatChanged> PublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class
{
Dictionary<string, WhatChanged> changes = null;
if (self != null && to != null)
{
var type = typeof(T);
var ignoreList = new List<string>(ignore);
foreach (System.Reflection.PropertyInfo pi in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
if (!ignoreList.Contains(pi.Name))
{
var selfValue = type.GetProperty(pi.Name).GetValue(self, null);
var toValue = type.GetProperty(pi.Name).GetValue(to, null);
if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)))
{
if (changes == null)
changes = new Dictionary<string, WhatChanged>();
changes.Add(pi.Name, new WhatChanged
{
OldValue = selfValue,
NewValue=toValue
});
}
}
}
return changes;
}
return null;
}
Coming in very late here, but I created a library to do this on MVC models and providing "readable" diffs for humans using MVC ModelMetadata:
https://github.com/paultyng/ObjectDiff
It gives me output when I save a Model similar to:
Status: 'Live', was 'Inactive'
Phone: '123-456-7898', was '555-555-5555'
Etc.
use the TempData Dictionary.
TempData["previousValue"];
TempData["newValue"];