Binding knockoutjs / mapping in ASP.NET with EF objects - c#

I am trying to bind a select and table to the result of an AJAX call in ASP.NET with the objects coming from EntityFramework backend.
Here is the script:
<script type="text/javascript">
function QuizListViewModel() {
var self = this;
self.quizList = ko.observableArray([]);
}
var qlvm = new QuizListViewModel();
ko.applyBindings(qlvm);
function FetchQuizzes() {
$.getJSON(
"/DesktopModules/personify/QuizAdminDos/API/QuizAdmin/QuizList",
function (result) {
var mapping = {
'observe': ["IdQuiz", "Name"]
}
parsedJsonQuizzes = jQuery.parseJSON(result);
console.log(parsedJsonQuizzes);
ko.mapping.fromJS(parsedJsonQuizzes, mapping, qlvm.quizList);
});
}
$(document).ready(function () {
FetchQuizzes();
});
</script>
Here is the View:
<select data-bind="options: quizList,
optionsText: function(quiz) { return quiz.Name() + '(Id: ' + quiz.IdQuiz() + ')'},
optionsCaption: 'Select a quiz...'"></select>
I have verified through debugging that I am getting objects back from my JSON call. I have also verified that the 'quizList' observable has values after the ko.mapping.fromJS call. However, nothing is showing in my select. I don't even get the "optionsCaption" value.
Am I allowed to bind directly to EF objects (generated from the DB)? Here is what is coming back from the console.log output of the parsedJsonQuizzes:
And for full disclosure, this is how I am returning the objects from my AJAX call:
using (var db = new LinuxDatabase())
{
List<Quiz> qzs = db.Quizs.ToList();
db.ContextOptions.LazyLoadingEnabled = false;
var json = JsonConvert.SerializeObject(qzs);
return Request.CreateResponse(HttpStatusCode.OK, json);
}
Thanks for the help!

I think you need to move your call to applyBindings into your $(documnent).ready function so that you can ensure the DOM has been loaded before you're trying to bind.

Related

Update C# variable via Ajax?

I have got a page full of posts, I sort those posts before rendering it.
Now I have created a drop down so user's can sort the posts by newest or oldest.
The only problem is I don't know how to update the server-side variable through Ajax.
#{
var SortSelected = "";
var sortedArticles = ListOfPosts.OrderBy(x => x.GetPropertyValue<DateTime>("articleDate")).Reverse().ToList();
if (SortSelected == "Most recent")
{
sortedArticles = ListOfPosts.OrderBy(x => x.GetPropertyValue<DateTime>("articleDate")).Reverse().ToList();
}
else if (SortSelected == "Oldest")
{
sortedArticles = ListOfPosts.OrderBy(x => x.GetPropertyValue<DateTime>("articleDate")).ToList();
}
}
I have removed other code which is irrelevant to make it cleaner.
That's my code for the posts, this is the Razor(html)
<div class="AnimatedLabel">
<select name="contact" class="tm-md-12">
<option id="hide-selector-dropdown" value=""></option>
#foreach (var item in FilterTypes)
{
<option value="#item">#item</option>
}
</select>
<label for="contact">Sort by</label>
<span class="tm-icon-arrow--right" id="selector-dropdown-arrow"></span>
</div>
This is how I tried to do it -
<script>
$('select').on('change', function () {
SortSelected = this.value;
});
</script>
But it is not updating the value, I have been told because it is server-side.
I know people will probably roast me for this question but I do not know any other solution so any help would be great!
I do not have much experience with .net/c#
Thanks!
Okay, so I just wanted to show you how you can achieve something like this using AJAX. As far as I have understood, you want to sort your posts list based on the selection from the user in the dropdown list that you have. Please refer to the code snippet below and let me know if you were able to get what you wanted regarding your requirement:
<script>
$('select').on('change', function () {
//SortSelected = this.value;
//First get the text of the selected item
var selectedText=$('#hide-selector-dropdown :selected').text();
//Now generate your JSON data here to be sent to the server
var json = {
selectedText: selectedText
};
//Send the JSON data via AJAX to your Controller method
$.ajax({
url: '#Url.Action("ProcessMyValue", "Home")',
type: 'post',
dataType: "json",
data: { "json": JSON.stringify(json)},
success: function (result) {
//Show your list here
if (data.success) {
console.log(data.sortedArticles);
}
else {
console.log("List empty or not found");
}
},
error: function (error) {
console.log(error)
}
});
});
</script>
Your Controller would look like:
using System.Web.Script.Serialization;
[HttpPost]
public ActionResult ProcessMyValue(string json)
{
var serializer = new JavaScriptSerializer();
dynamic jsondata = serializer.Deserialize(json, typeof(object));
//Get your variables here from AJAX call
var SortSelected= jsondata["selectedText"];
//Do something with your variables here. I am assuming this:
var sortedArticles = ListOfPosts.OrderBy(x => x.GetPropertyValue<DateTime>("articleDate")).Reverse().ToList();
if (SortSelected == "Most recent")
{
sortedArticles = ListOfPosts.OrderBy(x => x.GetPropertyValue<DateTime>("articleDate")).Reverse().ToList();
}
else if (SortSelected == "Oldest")
{
sortedArticles = ListOfPosts.OrderBy(x => x.GetPropertyValue<DateTime>("articleDate")).ToList();
}
return Json(new { success = true, sortedArticles }, JsonRequestBehavior.AllowGet);
}
You can't change server variable value but you can use this for refresh your table.
<script>
$('select').on('change', function () {
$.get('/Url' , {sortBy:this.value}).done(function(result){
$('#yourTable').html(result);
}).fail(function(){
alert('Error !');
});
});
</script>
You can call web method in server side using ajax.
Use that method to update variable on server side

Iterate Session variable in Jquery

I have a .net MVC Project. I assigned a List to a session variable. And in the View, i use jquery to iterate the data in the session variable.
ie,
var doctors = #Html.Raw(Json.Encode(HttpContext.Current.Session["DoctorList"]));
doctorCount = doctors.length;
for(i=0;i<doctorCount ; i++)
{
var totalinvoice =0;
rows = "<tr><td style='text-align:center'>"+ (parseInt(i, 10)+1) +"</td><td colspan='6'><b>" + doctors[i].D_Name + "</b></td></tr>"
$(rows).appendTo("#tbl_doctorwise tbody");
}
This code some time gives null even if the session variable contains list value. But sometimes it works.
Is there any other method to loop a session variable in the mvc view (jquery)?
how I get the session value in jquery ??? ( session variable contains list )
If you are making an ajax call and setting this session item in your action method, it won't available in your original view as that view code was already executed when you requested the action method for that view.
What you should do is, instead of setting this data in session, return that as json from your action method.
[HttpPost]
public ActionResult GetDoctorwiseReport(DateTime fromDate,DateTime toDate)
{
var doctorList = new List<Doctor>();
//populate this list now
return Json(doctorList);
}
and now in your ajax call's success handler will receive this data and you can loop through them.
success: function(data) {
$.each(data,function(ind,item)
{
//build your html here as needed.
console.log(item);
});
}
<script>
$(function ()
{
var doctors= #Html.Raw(Json.Encode(HttpContext.Current.Session["DoctorLis‌​t"]))
$.each(doctors, function (index, value)
{
var totalinvoice =0; rows = "<tr><td style='text-align:center'>"+ (parseInt(i, 10)+1) +"</td><td colspan='6'><b>" + value.D_Name + "</b></td></tr>"
$(rows).appendTo("#tbl_doctorwise tbody");
})
});
</script>

Need to persist value selected in dropdownlist in MVC View Using Angular

I am new to both MVC and AngularJs so please excuse me if this is a stupid question. I have a dropdownlist in an Asp.net MVC View that is populated using AngularJs. When the user selects a Company in the dropdown list, I use the companyId to populate an unordered list. My problem, I need to use that same selected CompanyID in another controller and C# method. I have found some info on saving data in a service to reuse it, but I'm not sure if that is what I really need here (or if there is a simpler way to do it than creating a service), but if it is, I don't know how to save the value in a service.
Here is my View code:
{{company.vchCompanyName}}
Current Dashboard Modules:
{{m.vchRankingWidgetModuleHeaderText}}
Here is my Angular Controller code:
myApp.controller("CompanyController",
function($scope, $timeout, companyService)
{
getCompanies();
function getCompanies() {
companyService.getCompanies()
.success(function (data) {
$scope.companies = data;
})
.error(function (error) {
$scope.status = 'Unable to load customer data: ' + error.message;
});
};
$scope.getCurrentModules = function(){
companyId = $scope.company;
companyService.getCurrentModules(companyId)
.success(function (newdata){
$scope.currentModules = newdata;
});
}
});
Here is my Angular Service:
angular.module('dashboardManagement')
.service('companyService', ['$http', function ($http) {
this.getCompanies = function () {
return $http.get('/Home/GetAllCompanies');
};
this.getCurrentModules = function (id) {
return $http.get('/Home/GetCurrentModules?companyId=' + id);
};
}
]);
Any assistance is greatly appreciated!
I tried using the Service but I cannot get it to work. I need to show Business Units for a company if the Business Units checkbox is checked. I put the function "getBusinessUnits" on the ng-checked and tried to use the service to retrieve the CompanyID. My View looks like this:
<div ng-controller="BusinessUnitsController">
<input id="ckBusinessUnit" type="checkbox" ng-checked="getBusinessUnits()"/>Exclude by Business Units<br />
<ul>
<li ng-repeat="unit in businessUnits">{{unit.Description}}</li>
</ul>
</div>
My Controller looks like this:
myApp.controller("BusinessUnitsController",
function ($scope, $timeout, companyService) {
$scope.getBusinessUnits = function () {
companyId = companyService.selectedCompanyId;
companyService.getBusinessUnits(companyId)
.success(function (data) {
$scope.businessUnits = data;
});
};
});
The code in the Service is exactly as you suggested:
angular.module('dashboardManagement')
.service('companyService', [
'$http', function ($http) {
this.selectedCompanyId = null;
this.getCompanies = function () {
return $http.get('/Home/GetAllCompanies');
};
this.getCurrentModules = function (companyId) {
this.selectedCompanyId = companyId;
return $http.get('/Home/GetCurrentModules?companyId=' + companyId);
};
this.getBusinessUnits = function (companyId) {
return $http.get('/Home/GetBusinessUnits?companyId=' + companyId);
}
}
]);
I'm obviously missing something.
The CompanyService can be used to stock a selectedCompanyId as a property.
angular.module('dashboardManagement')
.service('companyService', ['$http', function ($http) {
this.selectedCompanyId = null;
this.getCompanies = function () {
return $http.get('/Home/GetAllCompanies');
};
this.getCurrentModules = function (companyId) {
this.selectedCompanyId = companyId;
return $http.get('/Home/GetCurrentModules?companyId=' + companyId);
};
}]);
Then you can access the selectedCompanyId everywhere in your others controller/directive by injecting companyService.
Note that it is like a Singleton with a single instance, so you can have only one selected company for your whole angular application.
if I understand well you need to save the select companyId in your View and then pass it to your controller(c#) right?
try this, add a new property in your angularjs controller
$scope.SelectedCompanyId = '';
then in your dropdownlist add this attribute
ng-model="SelectedCompanyId"
then add a new hidden input
<input type="hidden" name="CompanyId" value="{{SelectedCompanyId}}" />
now if in the model that are you using in your view have a property CompanyId, when you do the post back it will map the value, or just in your controller add a new parameter
[HttpPost]
public ActionResult YourActionName(YourModel model, int? CompanyId)
{
//you can access to the CompanyId
//int? CompanyId --> this is only if your model doesn't have a property called CompanyId
}

How do I pass multiple objects from a ViewModel to a jQuery function?

I am coding a MVC 5 internet application and would like to know how to pass values from a ViewModel into a jQuery function where I have a list of data to pass.
Usually, I would create a hidden field in the MVC View code, and then retrieve this value in the jQuery code. However, in this situation, there is not just one value from the ViewModel, but a List of objects, where each object has many values.
My ViewModel has a List<MapMarker>, where each MapMarker has the following attributes:
latitude
longitude
title
draggable
This is the jQuery function that I need to call for each MapMarker object:
function LoadMapMarker(latitude, longitude, title, draggable)
How can I call the LoadMapMarker function, with data from each of the MapMarker objects in the ViewModel list?
Thanks in advance
You can serialize your list and storage it in a hidden field. Then call LoadMapMarker by means of Javascript on client side.
Server:
using System.Web.Script.Serialization;
var MapMarkers = new List<MapMarker>();
var jsonSerialiser = new JavaScriptSerializer();
var json = jsonSerialiser.Serialize(MapMarkers);
return View(new MyViewModel({JsonList = json }));
View:
<input type="hidden" id= "MyHiddenFieldForMapMarker" value="#Model.JsonList" >
Client:
var MapMarkers = $("#MyHiddenFieldForMapMarker").val();
for (var MapMarker in MapMarkers) {
LoadMapMarker(MapMarker["latitude"],
MapMarker["longitude"],
MapMarker["title"],
MapMarker["draggable"]);
}
You can serialize to JSON and then store in a hidden field, or as a Javascript object like :
myJsonData= [{"id":"15aea3fa","firstname":"John","lastname":"Doe"}];
Alternatively, you can retrieve the data via an ajax call.
If you don't want to use JSON and use the data you have on your page you can do this:
You can add class (or some other attribute, for me it is easier to use classes, but it is better "programming" to use another attribute)
#foreach ()...
{
<div class="main_Marker">
<input ... class="lat"/> //using the #Model render ofc...
<input ... class="long"/>
</div>
}
Then jQuery:
$("main_Marker").each(function(index, item)) {
var lat = $(item).child(".lat");
.
.
LoadMapMarker(lat, long....);
}
If your jQuery function is present in a view, use #Html.Raw(Json.Encode(Model.JSonData)) like this
//JavaScript or jQuery function
function javascriptFunction()
{
var data = #Html.Raw(Json.Encode(Model.JSonData))
}
In the above code, JSonData is the name of the collection variable that contains data from model. In your case a List.
If your jQuery function is in a separate JavaScript file, then an AJAX request can be used to get the data from model
Controller Code
public ActionResult GetData()
{
//Your logic to get data from model
//Here data is the variable that holds the collection List<MapMarker>
return Json(data);
}
JavaScript Code for AJAX Request
function myJavaScriptFunction()
{
$.ajax({
url: '/GetData',
type: 'post',
success: function (data) {
alert("data retrieved successfully");
},
error: function () {
alert("Error retrieving data");
}
});
}

Getting a framework to deal with knockout.js not persisting via hidden field

VS2013, WebForms, .NET 4.51
I want to use a hidden field to maintain the contents of my Knock Out view model across postbacks. So I took the KO code from http://knockoutjs.com/examples/cartEditor.html and then read http://www.codeproject.com/Articles/153735/Using-KnockoutJS-in-your-ASP-NET-applications for some ideas.
The end result is the following:
<asp:HiddenField ID="HiddenField1" runat="server" />
<script type='text/javascript' src="http://knockoutjs.com/examples/resources/sampleProductCategories.js"></script>
<script type="text/javascript">
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
var CartLine = function () {
var self = this;
self.category = ko.observable();
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function () {
return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
});
// Whenever the category changes, reset the product selection
self.category.subscribe(function () {
self.product(undefined);
});
};
var Cart = function () {
// Stores an array of lines, and from these, can work out the grandTotal
var self = this;
self.lines = ko.observableArray([new CartLine()]); // Put one line in by default
self.grandTotal = ko.computed(function () {
var total = 0;
$.each(self.lines(), function () { total += this.subtotal() })
return total;
});
// Operations
self.addLine = function() {
self.lines.push(new CartLine());
SaveList();
};
self.removeLine = function(line) {
self.lines.remove(line);
SaveList();
};
self.save = function () {
var dataToSave = $.map(self.lines(), function (line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined
});
alert("Could now send this to server: " + JSON.stringify(dataToSave));
};
self.SaveList = function () {
var myHidden = document.getElementById('<%= HiddenField1.ClientID %>');
if (myHidden)//checking whether it is found on DOM, but not necessary
{
var dataToSave = $.map(self.lines(), function (line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined;
});
alert("Saving - " + JSON.stringify(dataToSave));
myHidden.value = JSON.stringify(dataToSave);
}
};
};
var stringViewModel = document.getElementById('<%=HiddenField1.ClientID %>').value;
var viewModel;
if (document.getElementById('<%=HiddenField1.ClientID %>').value == '') {
alert('Nothing In Hidden Field');
viewModel = new Cart();
} else {
viewModel = ko.utils.parseJson(stringViewModel);
for (var propertyName in viewModel) {
viewModel[propertyName] = ko.observable(viewModel[propertyName]);
}
}
ko.applyBindings(viewModel);
$(document.forms[0]).submit(function () {
alert('In Submit');
viewModel.SaveList();
});
</script>
So basically when the page loads we create a new instance of the Cart. And when the form is posted we successfully have the cart serialized to HiddenField1 and I can see the expected value in the code behind:
protected void btnSave_OnClick(object aSender, EventArgs aE)
{
if (HiddenField1.Value == null)
{
}
}
however after the postback the contents of stringViewModel
var stringViewModel = document.getElementById('<%=HiddenField1.ClientID %>').value;
is always blanl / empty? Why is that?
And then assuming I have the correct JSON is the following the correct way to apply it back to the view model?
viewModel = ko.utils.parseJson(stringViewModel);
for (var propertyName in viewModel) {
viewModel[propertyName] = ko.observable(viewModel[propertyName]);
}
EDIT: I tried a few things with no luck
Added all JS code to jQuert OnReady() handler
Tried using instead of ASP:HiddenField
In all cases in PostBack I can see the value assigned to the hidden field by SaveList(), but when the page is displayed again (after postback) the value of the hidden field is an empty string
For the first part, what you're doing is correct. Use the console (press F12 in your browser) to examine the hidden field, and check if it has the value. If you see it in the server side, it should be in the client side. You can also run js code, and set breakpoints to discover what the problem is. You can also add a PreRender handler in the server side, and add a breakpoint and debug to check that the Value has not been deleted in the server side (this event happens just before the page is rendered to be sent to the browser).
For the second part, the fastest way to do what you need is to use knockout mapping, which creates a model from a JavaScript object, or from JSON. You need to use this: ko.mapping.fromJSON. This will create a new viewmodel, which you can directly bind, from your JSON. (As you can read in the docs, you can customize how the view model is created).
However, what you're doing is quite strange. You normally use Knockout with Web API, or Web Services, or Page methods, without reloading the page. The model is recovered, and updated, changed, etc. through one of those technologies, using AJAX.

Categories