I have a partial view which is used to show a checkbox in a column of table in razor. When I click on any checkbox in the table its posting back to controller with Id of first row and not the Id of row in which the check-box is contained. The javascript function to post ajax request is "SaveChanges" as given below.
The hidden field "RecurrenceScheduleId" is the primary key id.
Am I doing something wrong here?
- Following are my view & controller action:
#model SMRDS.Model.RecurrenceSchedule
#using (Ajax.BeginForm("_LogOccurancePartial", "Schedule",
new AjaxOptions
{
UpdateTargetId = "tdOccurance",
HttpMethod = "post",
LoadingElementId = "btnProgress",
OnBegin = "dialogBegin",
OnSuccess = "updateSuccess",
OnFailure = "dialogFailure"
},
new { id = "frm-toggle" }))
{
#Html.HiddenFor(model => model.RecurrenceScheduleId)
#Html.CheckBoxFor(m => m.LogOccurences, new { #onclick ="SaveChanges(this)" })
}
<script>
function updateSuccess() {}
function dialogFailure() {}
function dialogComplete() {}
function dialogBegin() {}
function SaveChanges(checkboxInput) {
$.ajax({
type: 'POST',
url: '/Schedule/_LogOccurancePartial',
data: { newValue: checkboxInput.checked, id: $("#RecurrenceScheduleId").val() },
dataType: 'json',
success: function (response) {
//handle success
}
});
}
Controller Action :
public JsonResult _LogOccurancePartial(bool newValue,int id)
{
var result = BLL.Service.RecurrenceSchedules.UpdateLogOccurence(id, newValue);
return Json(new { result = result }, JsonRequestBehavior.AllowGet);
}
Update
Following is the html rendered for hidden fields. At present I have only two rows with Ids "40" & "41".
<input data-val="true" id="RecurrenceScheduleId"
name="RecurrenceScheduleId" type="hidden" value="40">
<input data-val="true" id="RecurrenceScheduleId"
name="RecurrenceScheduleId" type="hidden" value="41">
It is your responsibility to maintain unique ids when you use the helpers.
If you had a model
public class ViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
And your view contains a collection you can use a for loop with an index to override the id with unique values.
#model List<ViewModel>
#for(int i = 0; i < Model.Count(); i++)
{
#Html.HiddenFor(m => Model[i].Id, htmlAttributes: new { id = "item" + item.Id })
}
But you can also adjust your click handler so you don't need to find a hidden input by id.
#Html.CheckBoxFor(m => m.LogOccurences,
new { #class="trigger", data_rsid=m.RecurrenceScheduleId })
<script>
$("body").on("click", ".trigger", function(e) {
var rsId = $(this).data("rsid");
var checked = $(this).prop("checked");
var data = { newValue: checked, id: rsId }
$.ajax({ ... });
});
</script>
Related
I have a couple of drop down lists... The first of which has an onchange event that calls a Javascript funcction:
#for (int i = 0; i < Model.things.Count; i++)
{
<tr>
<td>
#Html.DropDownListFor(m => m.Category[i].ID, ViewBag.Category as SelectList, "Please select a Category", new { #class = "class1", onchange = "Changed(this)" })
</td>
<td>
#Html.DropDownListFor(m => m.SubCategory[i].ID, Enumerable.Empty<SelectListItem>(), "Please select a Sub Category", new { #class = "class2" })
</td>
</tr>
}
Within this function I am making an ajax call to a controller method that returns a SelectList:
function TrackerChanged(val) {
var id = val.value;
$j.ajax({
url: appRoot + 'Controller/Method',
type: 'post',
data: { 'id': id},
success: function (results) {
if (results) {
**** POPULATE SECOND DROPDOWN ABOVE ***
}
else {
alert("Error updating comment");
}
},
failure: function () {
alert("Error updating comment");
}
});
}
The Controller Method returns a SelectList:
public SelectList Method(id categoryID)
{
IEnumerable<SelectListItem> select = null;
// Populate the IEnumerable with SubCategory results to show in the second Drop Down
return new SelectList(select, "Value", "Text");
}
but as you may notice from the comment in my ajax success chunk - I do not know how I would bind my new results back to the controller.
Please can someone help. I have looked for some examples and nothing seems to be working for me.
I was trying to pass a whole object to the jsonresult method. but there are errors that occur. It might be the way I bound it but I'm not sure. I'm new to JS and KOJS. Once the Login button, which is bound to the LogUser method, is clicked, it should call the Authenticate(Employee p) method.
here is my class model
public class Employee
{
[Key]
public long AutoId { get; set; }
[Required]
Display(Name = "Employee ID")]
public string EmployeeId { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string EmployeePassword { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
}
this is my knockoutjs view model
$(function () {
ko.applyBindings(LoginVm);
});
//VIEW MODEL. MODEL IS BELOW THIS
var LoginVm = {
thisEmp: ko.observable(EmpObject),
LogUser: function () {
var self = this;
//trying to check if thisEmp properties has values by alerting
alert("ID: " + thisEmp.EmployeeId() + " Password: " + thisEmp.EmployeePassword());
$.ajax({
url: '/Employee/AuthenticateUser',
type: 'POST',
dataType: 'json',
data: ko.toJSON(thisEmp),
contentType: 'application/json',
success: function (errorMsg) {
if (errorMsg === '') {
}
}
});
}
};
//MODEL
var EmpObject = {
EmployeeId: ko.observable(''),
EmployeePassword: ko.observable('')
}
this is my view and how I bound the properties
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Employee</legend>
<div class="editor-label">
#Html.LabelFor(model => model.EmployeeId)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.EmployeeId, new { data_bind="value: thisEmp.EmployeeId()"})
#Html.ValidationMessageFor(model => model.EmployeeId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.EmployeePassword)
</div>
<div class="editor-field">
#Html.PasswordFor(model => model.EmployeePassword, new { data_bind="value: thisEmp.EmployeePassword()"})
#Html.ValidationMessageFor(model => model.EmployeePassword)
</div>B
<p>
#*<input type="submit" value="Create"/>*#
<input type="button" value="Login" data-bind="click: LogUser"/>
</p>
</fieldset>
}
this is the error
Uncaught TypeError: Unable to process binding "value: function (){return thisEmp().EmployeeId }"
Message: Cannot read property 'EmployeeId' of undefined
at value (eval at createBindingsStringEvaluator
The error is being thrown because you have defined LoginVm beforeEmpObject. You need to change the order they are declared.
Are you sure this is the code that produced this error? In your view you're binding thisEmp.EmployeeId() but th error says it's unable to bind thisEmp().EmployeeId. I think you tried both of them and the error still persisted. Either way, there is no need to make thisEmp an observable. It's enough that the properties are observables.
So, change your code to:
$(function () {
ko.applyBindings(new LoginVm());
});
//MODEL
var EmpObject = {
EmployeeId: ko.observable(''),
EmployeePassword: ko.observable('')
}
//VIEW MODEL. MODEL IS BELOW THIS
var LoginVm = function() {
var self = this;
self.thisEmp = EmpObject;
self.LogUser = function () {
var self = this;
//trying to check if thisEmp properties has values by alerting
alert("ID: " + self.thisEmp.EmployeeId() + " Password: " + self.thisEmp.EmployeePassword());
$.ajax({
url: '/Employee/AuthenticateUser',
type: 'POST',
dataType: 'json',
data: ko.toJSON(self.thisEmp),
contentType: 'application/json',
success: function (errorMsg) {
if (errorMsg === '') {
}
}
});
}
};
And change the bindings in view to:
#Html.TextBoxFor(model => model.EmployeeId, new { data_bind="value: thisEmp.EmployeeId"})
#Html.PasswordFor(model => model.EmployeePassword, new { data_bind="value: thisEmp.EmployeePassword"})
In this MVC application I've created cascading dropdown list i.e it will first populate countries list and after selecting country jquery's onchange event is called which will fetch the further states from the controller which further gets those data by edmx entity model in database.i have used ajax request to call the JSON method in this.After selecting states the new dropdown list would get activated for selecting Cities.Whenever I select countries from the drop down an alertbox pops out and says states retrieving failed.[object][object] also I didn't create relationship between tables as foreign key is that necessary
Location Controller:-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication3.Controllers
{
public class LocationController : Controller
{
//
// GET: /Location/
public ActionResult Index()
{
TestDBEntities db = new TestDBEntities();
ViewBag.Country = new SelectList(db.tblCountries, "CountryID", "CountryName");
return View();
}
public JsonResult GetState(string id)
{
List<SelectListItem> states = new List<SelectListItem>();
var stateList = this.Getstatevalue(Convert.ToInt32(id));
var stateData = stateList.Select(m => new SelectListItem()
{
Text = m.StateName,
Value = m.StateID.ToString(),
});
return Json(stateData, JsonRequestBehavior.AllowGet);
}
public IList<tblState> Getstatevalue(int CountryId)
{
TestDBEntities db = new TestDBEntities();
return db.tblStates.Where(m => m.CountryID == CountryId).ToList();
}
public JsonResult GetCity(string id)
{
List<SelectListItem> cities = new List<SelectListItem>();
var cityList = this.Getcityvalue(Convert.ToInt32(id));
var cityData = cityList.Select(m => new SelectListItem()
{
Text = m.CityName,
Value = m.CityID.ToString(),
});
return Json(cityData, JsonRequestBehavior.AllowGet);
}
public IList<tblCity> Getcityvalue(int StateId)
{
TestDBEntities db = new TestDBEntities();
return db.tblCities.Where(m => m.StateID == StateId).ToList();
}
}
}
Index.cshtml view
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>EmployeeData</legend>
<div class="editor-label">
#Html.Label("Country")<br />
</div>
<div>
#Html.DropDownList("Country", ViewBag.Country as SelectList, "-- Please Select a Country --", new { style = "width:150px", #id = "Country" })
</div>
<div class="editor-label">
<br />
#Html.Label("State")<br />
</div>
<div>
#Html.DropDownList("State", new SelectList(string.Empty, "Value", "Text"), "-- Please select a State --",
new { style = "width:150px", #class = "dropdown1" })
</div>
<div class="editor-label">
<br />
#Html.Label("City")<br />
</div>
<div>
#Html.DropDownList("City", new SelectList(string.Empty, "Value", "Text"), "-- Please select a city --",
new { style = "width:150px", #class = "dropdown2", #id = "City" })
</div>
<p>
<input type="button" onclick="ddlInsert()" value="Submit" />
</p>
</fieldset>
}
javascript code :
<script type="text/javascript">
$(document).ready(function () {
// this is Country Dropdown Selectedchange event
$("#Country").change(function () {
$("#State").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("Getstates")', // here we are Calling json method
dataType: 'json',
data: { id: $("#Country").val() },
// Get Selected Country ID.
success: function (states) {
$.each(states, function (i, state) {
$("#State").append('<option value="' + state.Value + '">' +
state.Text + '</option>');
});
},
error: function (ex) {
alert(' states retrieving fail.' + ex);
}
});
return false;
})
$("#State").change(function () {
$("#City").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("GetCities")', // here we are Calling json method
dataType: 'json',
data: { id: $("#State").val() },
// Get Selected Country ID.
success: function (cities) {
$.each(cities, function (i, city) {
$("#City").append('<option value="' + city.Value + '">' +
city.Text + '</option>');
});
},
error: function (ex) {
alert(' city retrieving fail.' + ex);
}
});
return false;
})
});
</script>
When I select a country in it No state gets loaded or populated into the dropdown list for states.
So, currently I have a collection of items where I want the user to be able to search using the name and some random text from the collection.
Here's what I have done so far:
public IEnumerable<Item> items = new[]
{
new Item { ItemId = 1, ItemName = "Apple", ItemDescription = "crispy, sweet", ItemPairing = "Walnut"},
new Item { ItemId = 2, ItemName = "Pear", ItemDescription = "slightly tart", ItemPairing = "Cheese"},
new Item { ItemId = 3, ItemName = "Banana", ItemDescription = "good source of potassium", ItemPairing = "Honey" },
new Item { ItemId = 4, ItemName = "Chocolate", ItemDescription = "Sweet and rich melting flavor", ItemPairing = "Wine"}
};
public ActionResult Index()
{
return View("Index");
}
public ActionResult Search(string search)
{
return View("Index", items.Where(n => n.ItemName.StartsWith(search)));
}
Here's the search part on the view:
<p>
<b>Search for Name:</b>
#Html.TextBox("ItemName", "", new { #class = "form-control" })
<b>Search for Text:</b>
#Html.TextBox("ItemText", "", new { #class = "form-control" })
<input id="search" type="submit" value="Search" onclick="search(ItemName,ItemText)" />
</p>
<script>
function search(ItemName, ItemText) {
$("search").click(function () {
$.ajax({
type: "POST",
url: "/Items/Search",
data: {ItemName, ItemText},
datatype: "html",
success: function (data) {
$('#result').html(data);
}
});
});
}
</script>
So that it can look something like this:
I want it so that when the user types in Apple for Name and Crispy for text, they can find the Apple item from my collection. I also want it so that if they type in either Name or Text, it will still return a matched item.
I'm not sure how to do that.
Remove the onclick attribute from the submit button and change it to
<button type="button" id="search">Search</button>
and change the script to
var url = '#Url.Action("Search", "Items")';
$("#search").click(function () {
$.post(url, { ItemName: $('#ItemName').val(), ItemText: $('#ItemText').val() }, function(data) {
$('#result').html(data);
});
})
Note you may want to consider making it $.get() rather than $.post()
and change the controller method to accept the inputs from both textboxes
public PartialViewResult Search(string itemName, string itemText)
{
var items = ??
// filter the data (adjust to suit your needs)
if (itemName != null)
{
items = items.Where(x => x.ItemName.ToUpperInveriant().Contains(itemName.ToUpperInveriant())
}
if (itemText != null)
{
items = items.Where(x => x.ItemDescription.ToUpperInveriant().Contains(itemText.ToUpperInveriant())
}
// query you data
return PartialView("_Search", items);
}
Side note: Its not clear what the logic for search is - i.e. if you enter search text in both textboxes, do you want an and or an or search
Assuming the view in the view in the question is Index.cshtml, then it will include the following html
<div id="result">
#Html.Action("Search") // assumes you want to initially display all items
</div>
and the _Search.cshtml partial would be something like
#model IEnumerable<Item>
#foreach (var item in Model)
{
// html to display the item properties
}
While CStrouble's answer will work, if you're into AJAX calls and want to sort this in a single page, you might consider using AJAX and JQuery calls.
With AJAX & JQuery:
var search = function(itemName, itemText) {
//note that if you want RESTful link, you'll have to edit the Routing config file.
$ajax.get('/controller/action/itemName/itemText/', function(res) {
//do stuff with results... for instance:
res.forEach(function(element) {
$('#someElement').append(element);
});
});
};
And the action:
public JsonResult SearchAction(itemName, itemText) {
List<Item> newItems = items.Where(x => x.ItemName.ToUpperInveriant().Contains(itemName.ToUpperInveriant())
|| x.ItemDescription.ToUpperInveriant().Contains(itemText.ToUpperInveriant())
|| x.ItemPairing.ToUpperInveriant().Contains(itemText.ToUpperInveriant()));
return Json.Encode(newItems.ToArray());
}
Note that I'm not home, so there might be some syntax errors.
Alright, so say I want to return a partial, instead of a simple array:
first, change the action to:
public ActionResult SearchAction(itemName, itemText) {
List<Item> newItems = items.Where(x => x.ItemName.ToUpperInveriant().Contains(itemName.ToUpperInveriant())
|| x.ItemDescription.ToUpperInveriant().Contains(itemText.ToUpperInveriant())
|| x.ItemPairing.ToUpperInveriant().Contains(itemText.ToUpperInveriant()));
return PartialView("~/Views/Partials/MyPartialView.cshtml", newItems);
}
And you create a partial view in the directory you specified, taking the model that you transferred (newItems)
#model IEnumerable<Path.to.Item>
<h3>Results</h3>
<ul>
#foreach(var item in model)
{
<li>#item.Name - #item.Description</li>
}
</ul>
and now when you receive the jquery response:
$.ajax({
type: "POST",
url: "/Items/Search",
data: {ItemName, ItemText},
datatype: "html",
success: function (data) {
$('#result').html(data);
}
});
//since data is the HTML partial itself.
//if you have firebug for Mozilla firefox, you can see what I'm
//talking about
You may want to consider converting both strings to upper or lower, depending on your search requirements. The below code assumes the search is case-insensitive.
public ActionResult Search(string search)
{
string upperSearch = search.ToUpperInvariant();
return View("Index", items.Where(n =>
n.ItemName.ToUpperInvariant().StartsWith(search) ||
n.ItemDescription.ToUpperInvariant().Contains(search)));
}
with the Or condition it will match if either the text or the name matches. If they match different items (like Apple and Tart), you may need to consider what happens in that use-case, but in this case it will return both Apple and Pear.
c# and jquery,
I have two drop-down lists(category and product), and have to change the product list based on the category.
#Html.DropDownList("categoryId", new SelectList(ViewBag.Category, "Id", "Name"), "Select Parent Category", new { #class = "form-control categorydata" })
#Html.DropDownList("productId", new SelectList(ViewBag.Product, "Id", "Name"), "Select Product", new { #class = "form-control product-list" })
And i am writing the following controller for getting the products list.It is worked.
[HttpGet]
public JsonResult GetProducts(int categoryId)
{
int tot = new Products().Total;
int cont = 1;
Category cat = new Category(2);
var products = new Products(cont, tot, cat);
// ViewBag.products = new Products(1,new Products().Total,new Category(categoryId));
return Json(products);
}
and my jquery is,
$('.categorydata').change(function () {
var selCat = $(".categorydata").val();
var url = "~/Add/GetProducts";
if (selCat.length != 0) {
$.get(url, { id: SelCat }, function (data) {
alert(data);
});
}
});
This jquery is didn't call the controller, and it can not get the data .
Please help me to solve it.
You should keep the property name in json data as same as the parameter name of the action method.
$.get(url, { categoryId : SelCat }, function (data) {
Refer the SO Post.
You should use this.
return Json(products,System.Web.Mvc.JsonRequestBehavior.AllowGet);
Try to put dataType: 'json' in you ajax call: