This is my LINQ code:
public JsonResult getfull()
{
var coursename = Session["course"].ToString();
var location = Session["location"].ToString();
var result = (from insti in db.Institute_Master
join course in db.Course_Detail on insti.InstituteId equals course.InstituteId
join coursemaster in db.Course_Master on course.CourseId equals coursemaster.CourseId
join facility in db.Facility_Detail on insti.InstituteId equals facility.InstituteId
join masterfacility in db.Facility_Master on facility.FacilityMasterID equals masterfacility.FacilityMasterId
where coursemaster.CourseName == coursename || insti.City == location
select new
{
//Id = insti.InstituteId,
name = insti.InstituteName,
university = insti.University,
Contact = insti.ContactNo,
address = insti.Address,
email = insti.EmailId,
zipcode = insti.Zipcode,
country = insti.Country,
state = insti.State,
city = insti.City,
start = insti.EstablishOn,
image = insti.ProfilePhoto,
fees = course.TotalFees,
mode = course.Mode,
coursename = coursemaster.CourseName,
duaration = coursemaster.duration,
discription = coursemaster.Discription,
eligibility = coursemaster.Eligibility,
recognization = coursemaster.Recognization,
facility = masterfacility.FacilityName
}).Distinct();
ViewBag.facilies = list;
return Json(result, JsonRequestBehavior.AllowGet);
}
This method is return json result which is handled by angular js and I mention angularjs code below.
I am using AngularJs To display a data and my record is repeating for particular facility.
This is my tables:
This is a problem that display same record again for his facility:
This is my Angularjs code
<h1>Show Institute</h1>
<div data-ng-app="myModule">
<div data-ng-controller="myController">
<ul class="w3-ul w3-card-4" data-ng-repeat="detail in employees">
<li class="w3-padding-16 institute-list">
<span class="w3-xlarge">{{detail.name | uppercase}}</span>,<span>{{detail.address}}</span><br>
<img alt="image" src="~/images/{{detail.image}}" class="w3-left w3-margin-right img-institute-list" style="width:60px" />
<span class="w3-xlarge">{{detail.coursename | uppercase}}</span>,<span>Course Duration {{detail.duaration}}</span>,<span>Course Mode {{detail.mode}}</span>,<span>{{detail.discription}}</span><br>
<span><b>Fees : </b>INR {{detail.fees}}</span><br>
<span><b>{{detail.recognization | uppercase}}</b> Recognised</span><br>
<span>Facility {{detail.facility}}</span>
<button class="w3-btn w3-blue" id="detail">More Details</button>
</li>
<script>
$(document).ready(function () {
$("button").click(function () {
$("#moredetail").toggle();
});
});
</script>
<li class="w3-padding-16 institute-list" id="moredetail" style="display:none">
<span class="w3-xlarge">{{detail.contact}}</span> <span class="w3-xlarge">{{detail.email}}</span><br />
<span class="w3-xlarge" >{{detail.zipcode}}</span> <span class="w3-xlarge" >{{detail.country}}</span> <br/>
<span class="w3-xlarge" >{{detail.state}}</span> <span class="w3-xlarge" >{{detail.city}}</span> <br />
<span class="w3-xlarge" >{{detail.start}}</span>,
</li>
</ul>
</div>
</div>
<script>
var app = angular
.module("myModule", [])
.controller("myController", function ($scope, $http) {
$http.get("/home/getfull")
.then(function (response) {
$scope.employees = response.data;
});
})
</script>
</div>
</body>
</html>
This code is for displaying data in a view view json method
Can anyone help me in this?
It keeps adding the same record because you have "select new". What you need is model like:
public class CourseModel
{
public int InstituteId {get; set;}
public string InstituteName {get; set;}
public string University {get; set;}
ETC...
}
Then in your MVC Controller:
var result = (from insti in db.Institute_Master
join course in db.Course_Detail on insti.InstituteId equals course.InstituteId
join coursemaster in db.Course_Master on course.CourseId equals coursemaster.CourseId
join facility in db.Facility_Detail on insti.InstituteId equals facility.InstituteId
join masterfacility in db.Facility_Master on facility.FacilityMasterID equals masterfacility.FacilityMasterId
where coursemaster.CourseName == coursename || insti.City == location
var courses = new List<CourseModel>();
foreach(var c in result)
{
courses.Add(new CourseModel
{
InstitueName = insti.InstituteName,
University = insti.University,
ETC...
});
}
return Json(courses, JsonRequestBehavior.AllowGet;
}
I hope this helps!
Related
I'm trying to save data on a table but for some reason the Select element of Html always saves the first DateTime option item instead of saving the one I selected.
Here I select the option corresponding to the date highlighted but when I save the information the first option (22-01-08) is the one that itยดs saved on the database table
My View Model:
public class BookNowViewModel
{
public string FilmeName { get; set; }
public DateTime FilmeDate { get; set; }
public string seatNum { get; set; }
public int Price { get; set; }
public int FilmeId { get; set; }
}
My Controller where i set the functions do save the data retrieved from the view to the "Cart" table:
[HttpGet]
public IActionResult BookNow(int Id)
{
BookNowViewModel vm = new BookNowViewModel();
var item = _context.Filme.Where(a => a.Id == Id).FirstOrDefault();
var it = _context.Sessao.Where(n => n.FilmeId == Id).FirstOrDefault();
vm.FilmeName = item.Name;
vm.FilmeDate = it.Date;
vm.FilmeId = Id;
vm.Price = Convert.ToInt32(item.Price);
ViewBag.FilmeDate = _context.Sessao.Where(a => a.FilmeId == Id)
.Select(i => new SelectListItem
{
Value = i.Id.ToString(),
Text = i.Date.ToString()
}).ToList();
return View(vm);
}
[HttpPost]
public async Task<IActionResult> BookNow(BookNowViewModel vm,int Id)
{
List<Cart> carts = new List<Cart>();
string seatNum = vm.seatNum.ToString();
int filmeId = vm.FilmeId;
var filme = _context.Filme.Where(a => a.Id == Id).FirstOrDefault();
var sessao = _context.Sessao.Where(n => n.FilmeId == Id).FirstOrDefault();
string[] seatNumArray = seatNum.Split(",");
count = seatNumArray.Length;
if (checkSeat(seatNum, filmeId) == false)
{
foreach (var item in seatNumArray)
{
carts.Add(new Cart
{
Price = Convert.ToInt32(filme.Price),
MovieId = vm.FilmeId,
UserId = _userManager.GetUserId(HttpContext.User),
Date = sessao.Date,
seatNum = item
});;
}
foreach (var item in carts)
{
_context.Cart.Add(item);
await _context.SaveChangesAsync();
//_context.SaveChanges();
}
TempData["Sucess"] = "Seat Booked, See your Cart";
}
else
{
TempData["seatnummsg"] = "Please Change you seat number";
}
return RedirectToAction("Index");
}
My View :
div class="col-md-4">
<form asp-action="BookNow" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FilmeName" class="control-label"></label>
#Model.FilmeName
<span asp-validation-for="FilmeName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FilmeDate" class="control-label"></label>
<select name="ok" id="FilmeDate" asp-for="FilmeDate" class="form-control" asp-items="ViewBag.FilmeDate"></select>
</div>
<div class="form-group">
<label asp-for="seatNum" class="control-label"></label>
<input asp-for="seatNum" class="form-control" />
<span asp-validation-for="seatNum" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FilmeId" class="control-label"></label>
<input asp-for="FilmeId" class="form-control" />
<span asp-validation-for="FilmeId" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Add to Cart" class="btn btn-default btn-success text-white" />
</div>
</form>
I can see a couple of issues here.
The <select> element has the wrong name attribute. You can remove name="ok" (and the id) as the tag-helper asp-for will automatically set the name and id attributes. It should correctly bind to the FilmeDate property if you change it to:
<select asp-for="FilmeDate" class="form-control" asp-items="ViewBag.FilmeDate"></select>
You're populating the ViewBag with dates, but you're assigning the value to the Id not the Date. Use the date in the value field too:
...
.Select(i => new SelectListItem
{
Value = i.Date.ToString(),
Text = i.Date.ToString()
}
However, another problem is that you're not using the value from the viewmodel when saving to the database. It looks like you're saving a value which you just read from the database: Date = sessao.Date. You should use the value from the ViewModel: Date = vm.FilmeDate.
...
// only 1 for loop required
foreach (var item in seatNumArray)
{
var cart = new Cart
{
Price = Convert.ToInt32(filme.Price),
MovieId = vm.FilmeId,
UserId = _userManager.GetUserId(HttpContext.User),
Date = vm.FilmeDate, // use the value selected the viewmodel
seatNum = item
};
_context.Cart.Add(cart);
}
// save changes after adding all items
await _context.SaveChangesAsync();
You only need a single loop and you can save changes after adding all items too. Since you're no longer using sessao in the Post method it can be removed.
Aside: if you're checking for seat availability for a particular film in checkSeat(seatNum, filmeId), you may also need to consider the film date too.
I need to create a form that collects multiple key-value pairs of data from the user. I am using a dictionary to model this data. In my form, the user inserts a key and value and if needs to add more than one pair then a (+) icon is pressed for new fields to appear. In case the user decides to delete a key and value pair, a delete icon needs to be clicked to remove the key-value pair. I started coding the behavior of the form with jQuery and JavaScript as the backend is made in C#, but soon it started to get more complicated. I have tried to use Razor page and asp tag helpers, but they are not helpful in creating the sequence of events as I would like to. I am wondering how such a situation can be addressed most appropriately in ASP.Net Core 2.2
<div id="otherProperty">
<i id="deleteProperty" class="material-icons">delete</i>
<input id="otherPropertyKey" name="propertyKey" type="text" placeholder="Property name"/>
<input id="otherPropertyValue" name="propertyValue" type="text" placeholder="Property value"/>
<i id="addProperty" class="material-icons">๎
</i>
</div>
<div>
<input id="submitBtn" type="submit" value="Submit"/>
</div>
The model for the OtherProperties is:
public class OtherProperties:IOtherProperties
{
private readonly Dictionary<string, string> _otherProperties;
public OtherProperties()
{
_otherProperties = new Dictionary<string, string>();
}
public Dictionary<string, string> GetOtherProperties()
{
return _otherProperties;
}
public void AddProperty(string key, string value)
{
if (!_otherProperties.ContainsKey(key))
{
_otherProperties.Add(key,value);
}
}
public void RemoveProperty(string key)
{
if (_otherProperties.ContainsKey(key))
{
_otherProperties.Remove(key);
}
}
}
Where the interface is
public interface IOtherProperties
{
Dictionary<string, string> GetOtherProperties();
void AddProperty(string key, string value);
void RemoveProperty(string key);
}
I finally resolved this by using JavaScript. Without Blazor, you can't use pure ASP.Net Razor to achieve this. The JavaScript code that I wrote is as follows:
<div id="otherProperties">
<div id="otherProperty-0">
<i id="deleteProperty-0" class="material-icons" onclick="RemoveProperty(id)">delete</i>
<input id="otherPropertyKey-0" name="propertyKey-0" type="text" placeholder="Property name"/>
<input id="otherPropertyValue-0" name="propertyValue-0" type="text" placeholder="Property value"/>
<i id="addProperty" class="material-icons" onclick="AddProperty()">๎
</i>
</div>
Then JavaScript code would be like this
var idCounter = 1;
var keyValuePairArray = ['0'];
function AddProperty() {
if(document.getElementById('deleteProperty-'.concat(idCounter-1)) !== null) {
document.getElementById('deleteProperty-'.concat(idCounter - 1)).style.visibility = 'visible';
}
var newProperty = GenerateOtherProperty(idCounter);
document.getElementById('otherProperties').insertAdjacentHTML('beforeend',newProperty);
keyValuePairArray.push(idCounter.toString());
idCounter = idCounter +1 ;
}
function RemoveProperty(id) {
//from id extract the number
var propId = id.toString().split('-')[1];
document.getElementById('otherProperty-'.concat(propId)).remove();
var index = keyValuePairArray.indexOf(propId.toString(),0);
if(index > -1){
keyValuePairArray.splice(index,1);
}
}
function KeyValuePair(key,value) {
this.key = key;
this.value = value;
}
function GetKeyValueInputBoxes() {
var otherProps = [];
for (i =0; i < keyValuePairArray.length; i++){
var key = GetElement('otherPropertyKey-'.concat(keyValuePairArray[i])).value;
var value = GetElement('otherPropertyValue-'.concat(keyValuePairArray[i])).value;
var kvp = new KeyValuePair(key,value);
otherProps.push(kvp);
}
return otherProps;
}
/**
* #return {string}
*/
function GenerateOtherProperty (counter) {
var rawOtherProperty = ' <div id="otherProperty">\n' +
' <i id="deleteProperty" class="material-icons" onclick="RemoveProperty(id)">delete</i>\n' +
' <input id="otherPropertyKey" name="propertyKey" type="text" placeholder="Property name"/>\n' +
' <input id="otherPropertyValue" name="propertyValue" type="text" placeholder="Property value"/>\n' +
' <i id="addProperty" class="material-icons" onclick="AddProperty()">๎
</i>\n' +
' </div>';
var freshProp = new DOMParser().parseFromString(rawOtherProperty,"text/html");
freshProp.getElementById("otherProperty").id = 'otherProperty-'.concat(counter);
freshProp.getElementById("deleteProperty").id = 'deleteProperty-'.concat(counter);
freshProp.getElementById("otherPropertyKey").id = 'otherPropertyKey-'.concat(counter);
freshProp.getElementById("otherPropertyValue").id = 'otherPropertyValue-'.concat(counter);
return freshProp.body.innerHTML;
}
So, by using JS we control the behavior of the UI and collect the values in the fields. We will convert the data to a JSON object and POST it as the raw body of a request to our Web API controller in the back.
[HttpPost]
[Route("api/event")]
public IActionResult ProcessForm([FromBody] JObject jsonRawBody)
{
var jsonData = JsonConvert.DeserializeObject<Event>(jsonRawBody.ToString());
// process jsonData
}
Where Event model is :
public class Event
{
[JsonProperty("otherKVP")]
public IList<KeyValuePair<string,string>> OtherProperties { get; set; }
}
Sorry for my english.
Data binding doesn't work.
All data correctly serializing and displayed, but if i try to change some value - nothing happens.
Klik() method working correctly, conditions works correctly.
Please, help.
HTML code
<div id="app">
<div class="areaInfo " v-for="area in mainObjects" v-on:click="klik(area)">
<div class="trDiv areaData">
<div class="tdDiv" v-for="(prop, key) in area" v-if="key != 'ChildData'">
{{key}}
<template v-if="key.includes('Start') || key.includes('End') ">
{{ ConvertJsonDateString(prop) }}
</template>
<template v-else-if="!key.includes('Id')">
{{ prop }}
</template>
</div>
<div class="tdDiv" > {{area.childSeen}}</div>
</div>
</div>
</div>
Script:
var mainObjects = #(Html.Raw(result.Content));
for (var i = 0; i < mainObjects.length; i++) {
mainObjects[i].childSeen = false;
for (var j = 0; j < mainObjects[i].ChildData.length; j++) {
mainObjects[i].ChildData[j].childSeen = false;
}
}
console.log(mainObjects);
var app = new Vue({
el: "#app",
data: mainObjects,
methods: {
klik: function (region) {
console.log(region.childSeen)
if (region.childSeen == false) {
console.log('wasFalse');
return region.childSeen = true;
}
return region.childSeen = false;
}
},
});
Model example:
public class Test
{
public string FirstName {get;set;}
public string LastName {get;set;}
public List<Rebenok> ChildData {get;set;}
}
public class Rebenok
{
public string FirstName {get;set;}
public string LastName {get;set;}
public List<Diagnosis> Diagnoses {get;set;}
}
public class Diagnosis
{
public string Name {get;set;}
public string Description {get;set;}
}
mainObjects reference is not changed. You need to deep copy to make Vue reactive
<div id="app">
<div class="areaInfo " v-for="(area, index) in mainObjects" v-on:click="klik(index)">
<div class="trDiv areaData">
<div class="tdDiv" v-for="(prop, key) in area" v-if="key != 'ChildData'">
{{key}}
<template v-if="key.includes('Start') || key.includes('End') ">
{{ ConvertJsonDateString(prop) }}
</template>
<template v-else-if="!key.includes('Id')">
{{ prop }}
</template>
</div>
<div class="tdDiv" > {{area.childSeen}}</div>
</div>
</div>
</div>
var app = new Vue({
el: "#app",
data () {
return {
mainObjects
}
},
methods: {
klik: function (index) {
const mainObjects = JSON.parse(JSON.stringify(mainObjects)) // deep copy
const region = mainObjects[index]
console.log(region.childSeen)
if (region.childSeen == false) {
console.log('wasFalse');
region.childSeen = true;
}
region.childSeen = false;
this.mainObjects = mainObjects // assign again
}
},
});
I have numerous data displayed in a table, let's say a long list of users (first name & last name), so I set up a paging feature to display the elements by pages via the PagedList NuGet package. I was inspired by this tutorial: https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
I implemented a drop-down list in my view, so that I can directly choose the number of elements to display per page. I managed to include a jQuery script that makes the page size update whenever the drop-down list has a new selected value.
Using the mentioned tutorial , I also added a search feature: submitting a string in a search form allows to filter the data.
My problem is: changing the page size by selecting a new value in the drop-down list after having done a search doesn't work: the search results are reset, all the entries being displayed instead. I guess I forgot to pass some parameter somewhere but I just can't figure out where...
Here is my controller:
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page, int? PageSize)
// Sort order is passed to view in order to keep it intact while clicking in another page link
ViewBag.CurrentSort = sortOrder;
// Ascending or descending sorting by first or last name according to sortOrder value
ViewBag.LastNameSortParm = String.IsNullOrEmpty(sortOrder) ? "lastname_desc" : "";
ViewBag.FirstNameSortParm = sortOrder == "firstname" ? "firstname_desc" : "firstname";
// Not sure here
if (searchString == null)
{
searchString = currentFilter;
}
// Pass filtering string to view in order to maintain filtering when paging
ViewBag.CurrentFilter = searchString;
var users = from u in _db.USER select u;
// FILTERING
if (!String.IsNullOrEmpty(searchString))
{
users = users.Where(u => u.lastname.Contains(searchString)
|| u.firstname.Contains(searchString)
}
// Ascending or descending filtering by first/last name
switch (sortOrder)
{
case "lastname": // Ascending last name
users = users.OrderBy(u => u.lastname);
break;
case "lastname_desc": // Descending last name
users = users.OrderByDescending(u => u.lastname);
break;
case "firstname": // Ascending first name
users = users.OrderBy(u => u.firstname);
break;
case "firstname_desc": // Descending first name
users = users.OrderByDescending(u => u.firstname);
break;
default:
users = users.OrderBy(u => u.lastname);
break;
}
// DROPDOWNLIST FOR UPDATING PAGE SIZE
int count = _db.USER.OrderBy(e => e.Id).Count(); // Total number of elements
// Populate DropDownList
ViewBag.PageSize = new List<SelectListItem>() {
new SelectListItem { Text = "10", Value = "10", Selected = true },
new SelectListItem { Text = "25", Value = "25" },
new SelectListItem { Text = "50", Value = "50" },
new SelectListItem { Text = "100", Value = "100" },
new SelectListItem { Text = "All", Value = count.ToString() }
};
int pageNumber = (page ?? 1);
int pageSize = (PageSize ?? 10);
ViewBag.psize = pageSize;
return View(users.ToPagedList(pageNumber, pageSize));
}
And my Index.cshtml view:
<script src="~/Scripts/jquery-3.2.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () { // Submit pageSizeForm when another pageSize value is selected
$("#pageSize").change(function () {
$("#pageSizeForm").submit();
});
});
</script>
#model PagedList.IPagedList<AfpaSIPAdmin.Models.USER>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Users management";
}
<h1>Users management</h1>
<!-- Creating a new entry in table -->
<p>
#Html.ActionLink("Create new user", "Create")
</p>
<!-- Filtering table entries -->
#using (Html.BeginForm("Index", "Users", FormMethod.Get, new { id = "filterForm" }))
{
<p>
Filter: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string, new { #placeholder = "First or last name..." })
<input type="submit" value="Apply"/>
</p>
}
<!-- Display table -->
<table class="table">
<tr>
<th>
#Html.ActionLink("Last name", "Index", new {
sortOrder = ViewBag.LastNameSortParm,
currentFilter = ViewBag.CurrentFilter
})
</th>
<th>
#Html.ActionLink("First name", "Index", new {
sortOrder = ViewBag.FirstNameSortParm,
currentFilter = ViewBag.CurrentFilter
})
</th>
<th style="min-width: 170px"></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td style = "min-width: 150px">
#Html.DisplayFor(modelItem => item.lastname)
</td>
<td style = "min-width: 150px">
#Html.DisplayFor(modelItem => item.firstname)
</td>
<td> <!-- Using images as buttons for actions -->
<a href="#Url.Action("Edit", "Users", new { id = item.Id })" title="Edit">
<img src="~/Content/images/edit.gif" />
</a>
<a href="#Url.Action("Details", "Users", new { id = item.Id })" title="Details">
<img src="~/Content/images/info.gif" />
</a>
<a href="#Url.Action("Delete", "Users", new { id = item.Id })" title="Delete">
<img src="~/Content/images/delete.gif" />
</a>
</td>
</tr>
}
</table>
<br/>
<!-- Paging -->
#using (Html.BeginForm("Index", "Users", FormMethod.Get, new { id = "pageSizeForm" }))
{
<div class="pager">
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) sur #Model.PageCount<br/>
#Model.Count of #Model.TotalItemCount elements
#Html.PagedListPager(Model, page => Url.Action("Index", new {
page,
sortOrder = ViewBag.CurrentSort,
currentFilter = ViewBag.CurrentFilter,
searchString = ViewBag.CurrentFilter,
pageSize = ViewBag.psize
}))
<!-- DropDownList for setting page size -->
Elements per page :
#Html.DropDownList("pageSize")
</div>
}
The reason is because you have 2 forms. When you submit the first form containing the textbox, the only value you send back to the controller is SearchString and all the other parameters in your method will be their default (for example when you return the view, PageSize will default to null and therefore return only 10 records even if the user previously selected say 50.
Likewise, when you submit the 2nd form containing dropdownlist for the page size, the value of SearchString will be null because its not sent in the request.
You need to have one form only containing both form controls. And if you wanted to send additional properties, for example the current sort order, then you can add those as query string values in the form element (for example, #using(Html.BeginForm("Index", "Users", new { sortOrder = .... }, FormMethod.Get))
I would also strongly recommend you use a view model containing the properties you need in the view and strongly bind to them rather than using ViewBag
public class UsersVM
{
public string SearchString { get; set; }
public int PageSize { get; set; }
public IEnumerable<SelectListItem> PageSizeOptions { get; set; }
.....
public IPagedList<USER> Users { get; set; }
}
View
#model UsersVM
...
#using(Html.BeginForm("Index", "Users", FormMethod.Get))
{
#Html.LabelFor(m => m.SearchString)
#Html.TextBoxFor(m => m.SearchString)
#Html.LabelFor(m => m.PageSize)
#Html.DropDownListFor(m => m.PageSize, Model.PageSizeOptions)
<input type="submit" value="Filter" />
}
....
<div class="pager">
Page #(Model.Users.PageCount < Model.Users.PageNumber ? 0 : Model.Users.PageNumber)
....
#Html.PagedListPager(Model.Users, page => Url.Action("Index", new {
page,
sortOrder = Model.CurrentSort,
currentFilter = Model.CurrentFilter,
searchString = Model.CurrentFilter,
pageSize = Model.PageSize
}))
</div>
and in the controller method, initialize a new instance of UsersVM and assign its properties
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page, int? pageSize)
{
UsersVM model = new UsersVM();
....
var users = from u in _db.USER select u;
....
pageSize = pageSize ?? 10;
model.PageSize = pageSize.Value;
model.Users = users.ToPagedList(pageNumber, pageSize);
model.PageSizeOptions = new List<SelectListItem> { .... };
return View(model);
}
Ok so i have a view with this so far
function AppViewModel() {
this.title = ko.observable("#Model.Title");
this.firstName = ko.observable("#Model.FirstName");
this.lastName = ko.observable("#Model.LastName");
this.fullName = ko.computed(function () {
return this.title() + " " + this.firstName() + " " + this.lastName();
}, this);
}
#{
var jsList = Html.Raw(JsonConvert.SerializeObject(ViewBag.Countries));
}
function newViewModel() {
var theAppViewModel = new AppViewModel()
var g = ko.mapping.fromJS(theAppViewModel);
var viewModel = { vm: ko.observable([]) }
viewModel.vm = ko.mapping.fromJS(#jsList);
ko.applyBindings(g);
}
// Activates knockout.js
$(document).ready(function () {
ko.applyBindings(new newViewModel());
});
<ul style="list-style-type: none; float: left; margin-top: 20px; ">
<li>
#Html.LabelFor(model => model.Title)
<input data-bind="value: title"/>
</li>
<li>
#Html.LabelFor(model => model.FirstName)
<input data-bind="value: firstName" />
</li>
<li>
#Html.LabelFor(model => model.LastName)
<input data-bind="value: lastName" />
</li>
<li>
Full Name
<Span data-bind="text: fullName"></Span>
</li>
<li>
Coutries:
<select data-bind="foreach: vm">
<option data-bind="text: CountryName"></option>
</select>
</li>
</ul>
My Controller has this on it,
public ActionResult Index()
{
//ViewBag.Message = "KO js in mvc 4";
ViewBag.Countries = new List<Country>(){
new Country()
{
Id = 1,
CountryName = "America",
Abbreviation = "USA"
},
new Country()
{
Id = 2,
CountryName = "United Kingdon",
Abbreviation = "UK"
},
new Country()
{
Id = 3,
CountryName = "Irland",
Abbreviation = "IRL",
}
};
var vm = new PersonViewModel()
{
Id = 1,
DateOfBirth = new DateTime(1993, 01, 22),
Title = "Miss",
FirstName = "Jamie",
LastName = "Oscar",
};
return View(vm);
}
I can return the List from the controller in a standard loop like this:
<select>
#foreach(var c in ViewBag.Countries)
{
<option>#c.CountryName</option>
}
</select>
But I would like to bind the results to the list Via Knockout.js.
Your current viewModel that is containing the countries list is not bound, the only bound View-Model is the g you're calling applyBinding() with. Also, there's no point calling applyBinding() twice (on the same element).
Try this instead:
$(document).ready(function() {
var vm = new AppViewModel();
vm.Countries = ko.mapping.fromJS(#jsList);
ko.applyBindings(vm);
});
<select data-bind="value: countryId,
options: Countries,
optionsText: 'CountryName',
optionsValue: 'Id'"></select>
Please keep in mind that the value directive is referring to the chosen CountryId of the person but you currently don't have such a field in your View-Model.
Consider adding it as well:
var vm = new PersonViewModel()
{
Id = 1,
DateOfBirth = new DateTime(1993, 01, 22),
Title = "Miss",
FirstName = "Jamie",
LastName = "Oscar",
CountryId = 1
};
function AppViewModel() {
this.title = ko.observable("#Model.Title");
this.firstName = ko.observable("#Model.FirstName");
this.lastName = ko.observable("#Model.LastName");
this.countryId = ko.observable(#Model.CountryId);
}
it has now come to my attention that I can now bind knockout Json result to a #html.DropDownListFor attribute helper and still bind my data from knockout I have a DropDown list that is populated by knockout json array object, but then also bind this to the MVC 4 model this can be then used in the controller and the passed back to WCF or Linq to SQL for database
#Html.DropDownListFor(m => m.SelectedAuthType,
(SelectList)Model.authlevellistItems,
new { id = "alddl", data_bind = " options: Countries, optionsText: 'CountryName', optionsValue: 'Id'" })
works perfectly with models now as well as JSON knockout results.