Knockout MVC, bind model & add object to model - javascript

How can I add an item to a List<ComplexObject> with KnockoutJS?
This is my model:
public class MyModel
{
public List<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
This is the client side script:
<script type="text/javascript">
var viewModel = ko.mapping.fromJS(#Html.Raw(Json.Encode(Model)));
ko.applyBindings(viewModel);
// attempt:
var newUser = [{ "Id": "13", "Name": "John" }];
</script>
How do I add newUser to the the viewModel?

I would do it in the following manner.
Create a User object
Create a mapping that maps your returned object to your new User object
Use a simple push to add a new User object
Please see full code below with comments
// 1. Create a User object
var User = function (Id, Name) {
self = this;
self.Id = Id;
self.Name = Name;
}
// 2. Create a mapping
var mapping = {
'Users': {
create: function(options) {
return new User(options.data.Id, options.data.Name);
}
}
}
var data = #Html.Raw(Json.Encode(Model));
var viewModel = ko.mapping.fromJS(data, mapping);
// output to verify binding
console.log(viewModel);
// 3. Add the new User object
viewModel.Users.push(new User(2, "Jim"));
// output to verify added user
console.log(viewModel.Users());
Update:
Here is a jsfiddle with it working against a list:
http://jsfiddle.net/6qsjz/12/
Update 2
The null issue seems to be that you are not initialising the collection, add a constructor to your model like this:
public MyModel()
{
Users = new List<User>();
}

See this fiddle...
http://jsfiddle.net/6qsjz/4/
It's a little more like you've got. The view model element, along with your rawData should be defined before your bindings are applied.
var rawData = { "OtherStuff": { }, "User": {"id": "1", "name": "Bob"} }
....
viewModel = new ViewModel(rawData);
ko.applyBindings(viewModel, document.getElementById('domElementToBind'));
I then showed 2 different examples of creating your objects. Check out the fiddle and follow up with any further questions.
-----EDITED-----
Here's the update so you can add more users. The key was just to make the User --> Users as an observable array and start pushing new users to it.
http://jsfiddle.net/6qsjz/13/
self.newUser = new User();
self.addUser = function() {
self.Users.push(self.newUser);
}
-----EDITED-----
Oops. That's what I get for not looking both ways.
http://jsfiddle.net/6qsjz/17/
self.addUser = function() {
self.Users.push(new User(self.newUser.id(), self.newUser.name()));

Related

How to define an object variable like this in JQuery?

I would like to create a variable and populate data and make the output of the variable like the following pseudo code:
myObj = {
"Title":"Test",
"Paragraphs":
[
{
"Order":"1",
"Id": "2"
},
{
"Order":"2",
"Id": "1"
},
{
"Order":"3",
"Id": "2"
}
]
}
And use JQuery to POST to MVC controller action at the back end using a defined data model:
public class TemplateBuilderViewModel
{
public string Title { get; set; }
// Not sure if I should use Dictionary or something else
public Dictionary<int, int> Paragraphs { get; set; }
}
I am not sure how to declare the variable and populate data into the variable with the data structure I want in the output.
Any suggestions? Thank you.
This is what I get working in the end in JQuery.
Declare an array type, use push to insert values and assgin the arrary variable into the object type variable.
var dict = [];
for (i = 1; i < counter; i++) {
var paragraphId = Id;
var order = order;
dict.push({
"ParagraphId": paragraphId,
"ParagraphOrder": order
});
}
var templateBuilder = {
TemplateTitle: title,
ParagraphTitle: "",
ParagraphTitleList: undefined,
ParagraphText: "",
ParagraphOrder: dict
};

dropdownlist not showing data properly

i have this dropdown list which get the data from db but does not display the data properly n the view
The codes are as follows:
View:
#Html.DropDownListFor(m=> Model.SystemRAteModel.Role, new SelectList(Model.SystemRAteModel.GetRole.Items),"Value","Text")
Model:
public class SystemRolesModel
{
public static RoleProvider Provider { get; internal set; }
public int ID { get; set; }
public String Role { get; set; }
public Boolean Status { get; set; }
public SelectList GetRole { get; set; }
}
Controller
public ActionResult Index()
{
IApplicationLogic app = new ApplicationLogic(session);
RateManagementModel RTM = new RateManagementModel();
var value = app.GetVatValue();
var freight = app.GetFreightValue();
// var systemrolemodel = new SystemRolesModel();
//var currency = new List<SelectList>();
// currency= app.GetListOfRoles();
//IList<string> ERModel = new List<string>();
//foreach (var _currency in currency)
//{
// var curent = _currency.ToString();
// ERModel.Add(curent);
//}
var sysmodel = new SystemRolesModel();
sysmodel.GetRole = getRoleSelectList();
RTM.SystemRAteModel = sysmodel;
ViewData["ViewVatValue"] = value;
//ViewData["ViewCurrency"] = new SelectList(currency);
//ViewBag.LocationList = freight;
ViewData["ViewFreightValue"] = freight;
return View("Index",RTM);
}
public SelectList getRoleSelectList()
{
IApplicationLogic app = new ApplicationLogic(session);
var roles = app.GetListOfRoles();
SystemRoles sr = new SystemRoles();
sr.Id = -1;
sr.Role = "--select role--";
roles.Add(sr);
IEnumerable<SystemRoles> sortedRoles = roles.OrderBy(d => d.Id);
IList<SystemRoles> _sortedRoles = sortedRoles.ToList();
return new SelectList(_sortedRoles, "Id", "Role");
}
i have tried everything on the net but cant get a hand on it. Please any help will do.OutPut of my System At the moment
You don't need to create a new SelectList again in View, as you are already creating that in controller side and passing it via Model, you should be able to directly use it in View like:
#Html.DropDownListFor(m=> Model.SystemRAteModel.Role,Model.SystemRAteModel.GetRole)
This should populate the dropdown with the values, but it would display same values for all the items for now, as your code is setting hard-coded same values for all properties here:
SystemRoles sr = new SystemRoles();
sr.Id = -1;
sr.Role = "--select role--";
roles.Add(sr);
You would need to change it to have proper values.
Another easy way can be to use the constructor of SelectList this way:
public SelectList getRoleSelectList()
{
IApplicationLogic app = new ApplicationLogic(session);
var roles = app.GetListOfRoles().OrderBy(x=> x.RoleID);
return new SelectList(roles.ToList(), "RoleID", "Role");
}
you will just need to replace RoldID and Role property name with the proerty names you have in the DTO.
Hope it helps.
See this example:
#Html.DropDownList("Name", Model.Select(modelItem => new SelectListItem
{
Text = modelItem.Name,
Value = modelItem.Id.ToString(),
Selected = modelItem.Id == "12314124"
}))

breeze doesn't recognize the modified entity

I have a breeze implementation where it takes a location object and displays the properties on the UI. I do a change to a few properties and try to save the changes, but breeze doesn't recognized the entity as changed. Following is my code:
[HttpGet]
[CustomAuthorize(Claims = "permission:CanViewLocationAttributes")]
public Location GetLocationById(int clientId, int locationId)
{
//returns a single Location object
}
Following is my client-side functionality to retrieve the entity and save the entity:
function getLocationById(clientId, locationId) {
var self = this;
return EntityQuery.from('GetLocationById')
.withParameters({ clientId: clientId, locationId : locationId })
.using(self.manager)
.execute()
.then(querySucceeded, this._queryFailed);
function querySucceeded(data) {
if (data.results.length > 0) {
return data.results[0];
}
logSuccess(localize.getLocalizedString('_RetrievedLocations_'), locations, true);
}
}
function saveLocationSettings(clientId) {
var self = this;
var saveOptions = this.manager.saveOptions.using({ resourceName: "SaveLocationSettings", allowConcurrentSaves: true });
var entitiesToSave = self.manager.getChanges();
return self.manager.saveChanges(entitiesToSave, saveOptions).then(saveSucceeded, saveFailed);
}
my problem is that here the value of entitiesToSave is 0, even after I make changes to the fields in UI and save them.
Following is how I bind the entity to my angular model:
function getLocationDetails() {
clientcontext.location.getLocationById($route.current.params.clientId, $route.current.params.id)
.then(function (data) {
basicLocationSettings.id = data.locationId;
basicLocationSettings.parent = data.fkParentLocationId;
basicLocationSettings.locationType = data.locationType;
basicLocationSettings.locationName = data.locationName;
basicLocationSettings.locationDisplayName = data.locationDisplayName;
basicLocationSettings.locationCode = data.locationCode;
basicLocationSettings.isActive = data.activeStatus;
basicLocationSettings.timeZone = data.fkTimeZoneId;
basicLocationSettings.usesAppointments = data.usesAppointments;
basicLocationSettings.availabilityWindowDays = data.availabilityWindowDays;
basicLocationSettings.appointmentCutOffDays = data.appointmentCutOffDays;
basicLocationSettings.dailySummaryEmailTime = data.dailySummaryEmailTime;
basicLocationSettings.reminderBeforeApptEmailTime = data.reminderBeforeApptEmailTime;
basicLocationSettings.saveLocationSettings = function () {
clientcontext.location.saveLocationSettings($route.current.params.clientId);
}
});
}
Can anyone explain what I'm doing wrong? This is my first attempt on breeze and I'm kind of stuck here.
It looks like you are copying the breeze location entity's property values into an pojo object variable named "basicLocationSettings". Any changes to basicLocationSettings will not be tracked by the breeze entity manager or reflected in the source breeze entity. You'll need to bind the actual breeze entity to your UI so that user data entry modifies the entity property values directly.
I modified my code as follows and now the save is working:
function getLocationById(clientId, locationId) {
var self = this;
var location = null;
return EntityQuery.from('GetLocationById')
.withParameters({ clientId: clientId, locationId : locationId })
.using(self.manager)
.execute()
.then(querySucceeded, this._queryFailed);
function querySucceeded(data) {
if (data.results.length > 0) {
location = data.results[0];
}
logSuccess(localize.getLocalizedString('_RetrievedLocations_'), locations, true);
return location;
}
}
Note that I'm returning a location object, and in my controller, I bind the location object to my POJO.
function getLocationDetails() {
clientcontext.location.getLocationById($route.current.params.clientId, $route.current.params.id)
.then(function (data) {
basicLocationSettings.location = data;
basicLocationSettings.saveLocationSettings = saveLocationSettings;
});
}
Now when I call saveChanges(), I pass the location object to the repository:
function saveLocationSettings() {
clientcontext.location.saveLocationSettings(basicLocationSettings.location);
}

MVC , JS change value textboxfor not posting

I have this modelView
public class Ue
{ public class uEkranModel
{
public List<Grup> Grup = new List<Grup>();
private List<Secim> _secim;
public List<Secim> secim
{
get
{
if (_secim == null)
_secim = new List<Secim>();
return _secim;
}
set { _secim = value; }
}
}
public class Secim
{
public Guid uGuid { get; set; }
public Guid fGuid { get; set; }
}
}
I need to fell the List secims items with JS and post it back to controller.
I have tried to :
1)initialize the list in the controller :
Controller :
gidecek.Data = new Models.Ucak.UcakDeneme.uEkranModel();
gidecek.Data.secim.Add(new Models.Ue.Secim { uGuid = new Guid() });
gidecek.Data.secim.Add(new Models.Ue.Secim { uGuid = new Guid() });
View :
#using (Html.BeginForm("deneme", "U", FormMethod.Post, new { id = "secimTamam", style = "display:none" }))
{
#Html.EditorFor(m => m.Data.secim[0])
#Html.TextBoxFor(m => m.Data.secim[0].uGuid, new {id="gidis" })
}
JS :
$("#Data_secim_0__ucusGuid").attr("value", index);
This way , when the code is executed the value field of the textboxfor is changed(when the JS fired) but when I check the post data in controller , it is NULL.
also tried :
$("#Data_secim_0__ucusGuid").val(index);
which doesnt cahnge the value of teh textbox.
What I need is to fill the model values with js and post the form with js as well.(The data user is selecting is different, I am just posting back the GUID of the items within a form.)
2 possible issues. Your getter is initializing a new List<Secim>. Try initializing it in the constructor
public class uEkranModel
{
public uEkranModel()
{
secim = new List<Secim>();
}
public List<Secim> secim { get; set;}
....
}
Also I have seen other posts on SO indicating problems posting back GUID's (and one solution that was accepted was to use a view model with the GUID's converted to strings)

Serialize enum to const JsonNet

I am using Asp MVC 3 application.
I have an Enum:
public enum EmployeesOptions
{
John = 1,
Peter = 2,
Andrew = 3
}
And a MyViewModel class
public class MyViewModel
{
public MyViewModel()
{
Employees = new List<EmployeesOptions>()
{
EmployeesOptions.John,
EmployeesOptions.Peter,
EmployeesOptions.Andrew
};
}
public IEnumerable<EmployeesOptions> Employees { get; set; }
}
My Controller:
public ActionResult Index()
{
var vm = new MyViewModel();
return View(vm);
}
In My Index View:
#model MyViewModel
<script type="text/javascript">
var jsonString = '#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(this.Model))';
var data = ko.mapping.fromJSON(jsonString);
omega.franchiseInfo = ko.mapping.fromJS(data);
</script>
My serialized data coming from the server looks like this:
Emplyees:[1,2,3]
I want to be like this:
Emplyees:["John","Peter","Andrew"]
What am I missing ?
Update:
var jsonString = '#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(this.Model, Newtonsoft.Json.Formatting.None, new Newtonsoft.Json.Converters.StringEnumConverter()))';
This do the job!
If you want this enum type always to be serialized with its string values, you can decorate it with a JsonConverter attribute and the StringEnumConverter class like this:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
[JsonConverter(typeof(StringEnumConverter))]
public enum EmployeesOptions
{
John = 1,
Peter = 2,
Andrew = 3
}
Then you don't need to specify any converter classes in the serializer options anymore.
I tried decorating a List property that holds Enum values with [JsonConverter(typeof(StringEnumConverter))] but understandably that didn't work since it should decorate the Enum type directly.
// Did not work!
[JsonConverter(typeof(StringEnumConverter))]
public List<Assessment.AssessmentFunction> SelectedFunctions { get; set; }
then I did as you suggested and it worked as expected.
var selectedFunctions = #Html.Raw(JsonConvert.SerializeObject(Model.SelectedFunctions,
new StringEnumConverter()))
Instead of Enum int values now I get Enum strings in the JavaScript code inside a Razor .cshtml view. Just what I needed in a specific situation.
Before
var selectedFunctions = #Html.Raw(Json.Encode(Model.SelectedFunctions))
// Output
var selectedFunctions = [3, 3, 2, 2, 2, 3, 2, 2]
After
var selectedFunctions = #Html.Raw(JsonConvert.SerializeObject(Model.SelectedFunctions,
new StringEnumConverter()))
// Output
var selectedFunctions = ["Nurse","Nurse","Doctor","Doctor","Doctor","Nurse","Doctor","Doctor"]
You are returning enums, and by default it will display the enum values. You can modify your model like this.
public class MyViewModel
{
public MyViewModel()
{
Employees = new List<EmployeesOptions>()
{
EmployeesOptions.John.ToString(),
EmployeesOptions.Peter.ToString(),
EmployeesOptions.Andrew.ToString()
};
}
public IEnumerable<EmployeesOptions> Employees { get; set; }
}
By using the .ToString() extension method we can convert enums to the exact thing they are representing to string format.

Categories

Resources