Binding the C# list to knockout observable array - c#

I have list of objects in my MVC model as below.
#Html.EditorFor(model => model.LstEmploymentHistory)
<button id="btnAddHistory" data-bind="click: addHistory">Add one</button>
I need to bind this to Knockout observable array on load.
<script type="text/javascript">
//Data
var History = function () {
var self = this;
self.CompanyName = ko.observable();
self.Designation = ko.observable();
self.StartDate = ko.observable();
self.EndDate = ko.observable()
};
var viewModelEmploymentHistory = function () {
// Operations
var self = this;
self.historyList = ko.observableArray([new History()]); // Put one line in by default
self.addHistory = function () { self.historyList.push(new History()) }
self.removeHistory = function (history) {
self.historyList.remove(history)
}
self.educationList = ko.observableArray([new Education()]); // Put one line in by default
self.addEducation = function () { self.educationList.push(new Education()) };
self.removeEducation = function (education) {
self.educationList.remove(education)
}
};
//Data
var Education = function () {
var self = this;
self.Degree = ko.observable();
self.YearOfPassing = ko.observable();
self.Percentage = ko.observable();
self.Institute = ko.observable()
};
//var masterVM = (function () {
// this.viewModelEducationalDetails = new viewModelEducationalDetails(),
// this.viewModelEmploymentHistory = new viewModelEmploymentHistory();
//})();
//ko.applyBindings(masterVM)
ko.applyBindings(new viewModelEmploymentHistory());
// ko.applyBindings(new viewModelEducationalDetails(), document.getElementById("containerEducation"));
//ko.applyBindings(new viewModelEmploymentHistory(), document.getElementById("containerHistory"));
</script>
Can any one please help me with the way to bind the C# list to the observable array on page load.?

You will need to use a format that JavaScript understands, like JSON..
So in your controller you'll need to serialise the model into a JSON string
something like:
Model.JsonString = JsonConvert.SerializeObject(Model.LstEmploymentHistory);
You can then consume this in your JavaScript/MVC, several way to do this. The easiest is to simply write it to an input
#Html.HiddenFor(h => h.JsonString);
Then read it in your js:
var Json = document.getElementById('JsonString').value;
and then turn this back into an array:
var array = JSON.Parse(Json);
You then need to bind that into your observable. You've not actually explained how this is supposed to work so I'll leave this one to you...

If you bind in Razor then you can use the following:
var myModel = {
LstEmploymentHistory: #Html.Raw(Json.Encode(Model.LstEmploymentHistory))
};

Related

C# mongoDB wont update array in database

I want to update array in my mongoDB collection. Posting new document works just fine, but it won't update array. Structure of my document is:
var document = new BsonDocument
{
{ "post_title", model.Title },
{ "post_text", model.Text },
{ "post_author", model.Author },
{ "post_picture", model.Picture },
{ "post_comments", new BsonArray() },
};
And my update function is:
[HttpPost]
[Route("api/PostInfo/{Comment}")]
public async Task Post(Comment comment)
{
try {
BsonObjectId oldId = new BsonObjectId(new ObjectId(comment.id.ToString()));
var mongoDbClient = new MongoClient("mongodb://127.0.0.1:27017");
var mongoDbServer = mongoDbClient.GetDatabase("nmbp");
var collection = mongoDbServer.GetCollection<PostInfo>("post");
var filter = Builders<PostInfo>.Filter.Eq(e => e._id, oldId);
var update = Builders<PostInfo>.Update.Push("post_comments", comment.comment);
await collection.FindOneAndUpdateAsync(filter, update);
var test = oldId.GetType();
}
catch
{
}
}
When debugging, i can see that post controller is triggered, and comment values are correct, but when I take a look in database, value of "post_comments" array is empty. No error is thrown in catch block. Am I doing something wrong?
It looks like the problem was in this line:
var filter = Builders<PostInfo>.Filter.Eq(e => e._id, oldId);
The correct one should look like this:
var filter = Builders<PostInfo>.Filter.Eq("_id", oldId);

Helper method for testing JsonResult in Nunit

Here is my controller that returns a JSON.
public JsonResult GetValues()
{
return Json(
new{
title = new {
text = "Hello World"
},
xAxis = new {
type = "List of countries"
labels = new {
rotation = 90
}
}
},JsonRequestBehavior.AllowGet);
}
And in my Nunit, i am testing as follows:
[Test]
public void TestGetValues()
{
var controller = new HelloWorldController();
var values = controller.GetValues() as JsonResult;
Assert.IsNotNull(data);
var title = values.Data.GetType().GetProperty("title")
.GetValue(values.Data,null);
var text = title.GetType().GetProperty("text").GetValue(title);
Assert.IsNotNull(text);
}
This works fine but i have to test several methods that has same properties which will require me to write same thing over and over again. How to write a helper method so that i can just pass in the controller and the property i want to test.
Something like this:
var checkText = GetJSonProperties(controllername, "data/title/text");
var checkXais = GetJSonProperties(controllernmae, "data/xAxis/Type");
How can i achieve this ?
I would just use a dynamic type.
var controller = new HelloWorldController();
dynamic values = controller.GetValues();
var title = (string)values.title;
Saves you writing helper methods, which themselves may need to be tested!

Refesh ViewData after call Jquery function MVC

I have to refresh the items of two ListBox after a dropdownlist value change.
The data of the ListBoxes is in the ViewData and i call a action controller from jquery function, but the ViewData after the call have the same data.
Here is the code:
$(document).ready( function () {
$('#users').change(function () {
var selectedValue = $('#users').val();
$.post('#Url.Action("GruposUsuario", "Grupos")', { usersId: selectedValue }, function () {
var gruposAsig = JSON.parse('#Html.Raw(Json.Encode(ViewData["gruposAsignados"]))');
var gruposDisp = JSON.parse('#Html.Raw(Json.Encode(ViewData["gruposDisponibles"]))');
$('#gruposAsignados').empty();
$('#gruposAsignados').addItems(gruposAsig);
$('#gruposDisponibles').empty();
$('#gruposDisponibles').addItems(gruposDisp);
});
});
$.fn.addItems = function (grupos) {
return this.each(function () {
var list = this;
$.each(grupos, function (index, itemData) {
var option = new Option(itemData.Text, itemData.Value);
list.add(option);
});
});
};
});
And the Controller Code:
[HttpPost]
public ActionResult GruposUsuario(string usersId)
{
AllUsers();
GruposAsignados(int.Parse(usersId));
//GruposDispobibles(int.Parse(usersId));
return Json("Usuario");
}
void GruposAsignados(int usersId)
{
var grupos = new BL.Grupos().GruposAsignados(usersId);
List<SelectListItem> list = new List<SelectListItem>();
foreach (var grupo in grupos)
{
SelectListItem selectList = new SelectListItem()
{
Text = grupo.GroupName,
Value = grupo.GroupsId.ToString()
};
list.Add(selectList);
}
ViewData["gruposAsignados"] = list as IEnumerable<SelectListItem>;
}
How can i refesh the ViewDatas after the event?
Razor code is parsed on the server before it is sent to the view. Your use of #Html.Raw(...) assigns vales to gruposAsig and gruposDisp that are the initial values of the ViewData properties (inspect the source when you first render the page).
In any case you method GruposAsignados() only returns a string with the value "Usuario". If you want to return json data to update the options in two dropdownlists, then you controller method should be
[HttpGet] // its a GET
public ActionResult GruposUsuario(string usersId)
{
var gruposAsignados= new BL.Grupos().GruposAsignados(usersId).Select(g => new
{
ID = g.grupo.GroupsId;
Name = g.GroupName;
}
var gruposDisponibles = // another query
return Json(new { Asignados = gruposAsignados, Disponibles = gruposDisponibles, JsonRequestBehavior.AllowGet);
}
Then the script should be
var asignados = $('#gruposAsignados'); // cache it
var disponibles = $('#gruposDisponibles');
$.getJSON('#Url.Action("GruposUsuario", "Grupos")', { usersId: selectedValue }, function (response) {
if(response) {
asignados.empty();
// or asignados.empty().append($('</option>').val('').text('-Please select-'));
$.each(response.Asignados, function(index, item) {
asignados.append($('</option>').val(item.ID).text(item.Name));
});
disponibles.empty();
$.each(response.Disponibles, function(index, item) {
disponibles.append($('</option>').val(item.ID).text(item.Name));
});
}
});
Side note: There is no need to create IEnumerable<SelectListItem>. The browser has no knowledge of what a C# class is and you just returning extra unnecessary data (the values of the Selected, Group and Disabled properties) which are never used.

Consume ASMX service using Sencha 2

I am just begining to learn Sencha.
I have an asmx that returns a List so the xml looks like;
<Result>
<string>One</string>
<string>Two><string>
</Results>
Now all I want to do is show that in a List.
So my Sench code looks like;
Ext.define('ListItem', {
extend: 'Ext.data.Model',
config: {
fields: ['text']
}
});
var treeStore = Ext.create('Ext.data.TreeStore', {
model: 'ListItem',
defaultRootProperty: 'items',
proxy: {
type: 'ajax',
url: 'http://localhost:81/MyASMX.asmx/Test'
}
});
Ext.application({
name: 'Sencha',
launch: function () {
Ext.create('Ext.NestedList', {
fullscreen: true,
store: treeStore,
detailCard: {
html: 'You are viewing the detail card!'
}
});
}
});
But I get an empty list with a title bar that is also empty.
With .Asmx you can also bind xml to your treestore
here is the code that might be help you
function BindData(dataxml)
{
dataxml = dataxml.replace(/>/g, ">");
dataxml = dataxml.replace(/</g, "<");
var doc;
if (window.ActiveXObject) { //IE
var doc = new ActiveXObject("Microsoft.XMLDOM");
doc.async = "false";
doc.loadXML(dataxml);
} else { //Mozilla
var doc = new DOMParser().parseFromString(dataxml, "text/xml");
}
var store = new Ext.getStore('treestore');
store.removeAll();
var DataLen = doc.getElementsByTagName('FirstNode').length;
for (var i = 0; i < DataLen; i++) {
var arrnodename = doc.getElementsByTagName('nodeName')[i].firstChild.nodeValue.replace(/\"/g, '');
var arrnodename2 = doc.getElementsByTagName('nodeName2')[i].firstChild.nodeValue.replace(/\"/g, '');
store.add({ C1: arrnodename[0], C2: arrnodename2[0]});
}
}

How to retrieve the result of javascript function in the serverside?

I have javascript function return array like this:
<script type="text/javascript">
function looping() {
var column_num = 1;
var array = [];
$("#columns ul").not("#column1").each(function() {
var ulId = $(this).attr("id");
var ulClass = $(this).attr("class");
if (ulId != undefined && ulClass != undefined) {
var order = -1;
column_num++;
$("li", $(this)).each(function() {
var liId = $(this).attr("id");
var liClass = $(this).attr("class");
if (liId != undefined && liClass != undefined) {
order++;
var result = liId + "|" + liClass + "|" + column_num + "|" + order;
array.push(result);
//alert(array[0]);
}
});
}
});
return array;
}
</script>
How can I retrieve the result in another array in my code behind .cs in button click event?
The only way i see is send result using POST or GET AJAX request.
$.get("/server/page.aspx", { looping: looping() });
On ServerSide do:
var array = Request.Params["looping"];
Store the array in a hidden field <input type="hidden" name="hidfld" id="hidfld" /> inside your form.
document.getElementById("hidfld").value = array;
On the serverside, use the hidden field's name to retrieve the array

Categories