I want to load an external Json data File which contain the city name of a country.I want to show it in the search option in Index.cshtml.My Json file look like this-
CityName[
{
"City": "Flensburg"
},
{
"City": "Kiel"
},
{
"City": "Lübeck"
},
{
"City": "Neumünster"
}
]
Now I created City class inside the Model to get the name from this object.
public class City
{
public string City { get; set; }
}
My Controller Class look like this-
public class HomeController : Controller
{
public ActionResult Search(string name)
{
return View();
}
}
Now for the view I used Javascript and created one search box with button like this-
<div class="search-form">
<form action="index.html" method="get">
<div class="input-group">
<input type="text" placeholder="Enter Location Name" name="search" class="form-control input-lg">
<div class="input-group-btn">
<button class="btn btn-lg btn-primary" type="submit">
Search
</button>
</div>
</div>
</form>
</div>
Now I want to set the city name in the search option. But as I am very new in handling MVC, I am not sure how to proceed with it.
I think you should provide a dropdown with the available cities instead of a text input. As an alternative, use an autocompleter. Here is the solution with a dropdown.
First, you should create two Actions, one to display the page initially [HttpGet] and one to handle the post of the form [HttpPost].
The GET action should return a strongly typed view, the ViewModel contains your search parameters.
The View sends the filled out ViewModel to the post action.
public class SearchViewModel {
public City SelectedCity {get; set;}
// to be read from JSON
public City[] AvailableCities {get; set;}
// generate SelectListItems to be used with DropDownListFor()
public IEnumerable<SelectListItem> CityOptions { get {
foreach (var city in AvailableCities) {
yield return new SelectListItem {
Value = city.City,
Text = city.City,
Selected = city == SelectedCity
};
}
}}
}
// GET action
[HttpGet]
public ActionResult Search() {
var vm = new SearchViewModel();
vm.AvailableCities = // load from JSON
return View("Search", vm);
}
// Razor View <ControllerName>\Search.cshtml
#model SearchViewModel
#using (Html.BeginForm("Search", "<ControllerName>", FormMethod.Post)) {
#* render Cities dropdown; bind selected value to SelectedCity *#
#Html.DropDownListFor(m => m.SelectedCity, Model.CityOptions)
<button class="btn btn-lg btn-primary" type="submit">Search</button>
}
// POST Action
[HttpPost]
public ActionResult Search(SearchViewModel vm) {
var selected = vm.SelectedCity;
// search ...
}
"ControllerName" should be the name of the controller implementing the actions, e.g. "Home".
Related
I have a view inside which there are two checkboxes. On checked I need to save currently assigned value into database table.
Here is the model:
public class RoomHk
{
public int RoomHkId { get; set; }
public int RoomId { get; set; }
public DateTime? DeepCleaning { get; set; }
public DateTime? NewLinen { get; set; }
}
This is the child table of my Room Table. Following is my view, suppose user check on first checkbox then he clicks on save button, then I want to save current datetime in the NewLinen column of the RoomHk table to that respective RoomId. How can I do it with jQuery post method?
<div class="col-6">
#if (item.NewLinen == null)
{
<input type="checkbox" data-nlid="#item.RoomId" class="form-check-input newLinen" />
<label>New Linen</label>
<br />
}
#if (item.DeepCleaning == null)
{
<input type="checkbox" data-dcid="#item.RoomId" class="form-check-input deepClean" />
<label>Deep Cleaning</label>
}
</div>
<button type="button" class="btn btn-default insert" data-rid="#item.RoomId">Save</button>
$(function () {
$('.insert').click(function () {
$.post("#Url.Action("SetCleaningStatus", "HouseKeeping")", { id: $(this).data("id"), });
});
});
You could use Html.BeginForm and place the submit button inside the form. This is important, otherwise you'll need to employ additional scripts to get it working.
If you need to post the state of the two checkboxes (DeepCleaning and NewLinen) I'd suggest having them as Boolean instead of DateTime so you can have their states (checked/unchecked) mapped to the respective properties, because you seem to want to do that.
SetCleaningStatus.cshtml
#model RoomHk;
#Html.BeginForm("SetCleaningStatus", "HouseKeeping")
{
<!-- Will be posted to the controller, no additional Javascript necessary -->
#Html.HiddenFor(m => m.RoomId)
<div class="col-6">
#if (item.NewLinen == null)
{
<input type="checkbox" data-nlid="#item.RoomId" class="form-check-input newLinen" />
<label>New Linen</label>
<br />
}
#if (item.DeepCleaning == null)
{
<input type="checkbox" data-dcid="#item.RoomId" class="form-check-input deepClean" />
<label>Deep Cleaning</label>
}
</div>
<!-- IMPORTANT: the type needs to be `submit` instead of `button` -->
<input type="submit" class="btn btn-default insert" value="Save" />
}
HouseKeeping.cs
public class RoomHk
{
public int RoomHkId { get; set; }
public int RoomId { get; set; }
public DateTime? DeepCleaning { get; set; }
public DateTime? NewLinen { get; set; }
}
[HttpGet]
public ActionResult SetCleaningStatus()
{
var model = new RoomHk();
return View(model);
}
[HttpPost]
public ActionResult SetCleaningStatus(RoomHk arg)
{
bool response = new {
success = true
};
// Here is your RoomId
arg.RoomId;
arg.NewLinen = DateTime.Now;
// Save posted data to DB
// ...
// Return your response here
return Json(response);
}
POSTting the checked state of checkboxes
Use Html.CheckBoxFor and Html.LabelFor and let the compiler render those fields for you, with the right IDs and names properly set.
public class RoomHk
{
// Make them booleans
public bool DeepCleaning { get; set; }
public bool NewLinen { get; set; }
}
<div class="col-6">
<!--
<input type="checkbox" data-nlid="#item.RoomId" class="form-check-input newLinen" />
<label>New Linen</label>
<br />
-->
#Html.LabelFor(m => m.NewLinen, "New Linen")
#Html.CheckBoxFor(m => m.NewLinen, new { #class = "form-check-input" })
</div>
When clicking a button I am calling a web api with ajax. My form is using JqueryVal, to make form validations, according to my viewmodel data annotations.
My problem is that when I click the button "Listo" in my form, it calls my API, inspite of jqueryval is marking an error( selecting a file is required)
This is my code:
My viewmodel that contains data annotations(the dataannotations are used along with the jquery.validate.js and jquery.validate.unobtrusive.js. As you can see, it is working, but is not preventing the API from being called):
public class CursoViewModel
{
public Guid Id { get; set; }
[MaxLength(125)]
public string Titulo { get; set; }
[Required]
public string Descripcion { get; set; }
[Required(ErrorMessage ="selecciona una imagen para tu curso")]
[DataType(DataType.Upload)]
public HttpPostedFileBase Imagen { get; set; }
}
The class posted to my api
public class person
{
public string name { get; set; }
public string surname { get; set; }
}
The Api code
[HttpPut]
[Route("api/ProfesorCurso/test")]
public string Put(person p)
{
return p.name + p.surname;
}
My View
#model project.ViewModels.CourseViewModel
<form id="Editcurso" method="post" action="#">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "Please fix the following errors.")
<div class="container">
<div class="form-group">
#Html.LabelFor(c=>c.Titulo)
#Html.TextBoxFor(c => c.Titulo, new {id="titulo", #class="form-control"})
#Html.ValidationMessageFor(m => m.Titulo)
</div>
<div class="form-group">
#Html.LabelFor(c => c.Descripcion)
#Html.TextAreaFor(c => c.Descripcion, new {id="descripcion", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Descripcion)
</div>
<div class="thumbnail" id="imagencurso"></div>
<div class="form-group">
#Html.LabelFor(m => m.Imagen)
#Html.TextBoxFor(m => m.Imagen, new {id="imagen" ,type = "file", data_rule_validCustomer = "true" })
#Html.ValidationMessageFor(m => m.Imagen)
</div>
<button id="submiter" type="submit" class="btn btn-primary">Listo!</button>
</div>
</form>
The scripts in the view
#section scripts
{
#Scripts.Render("~/bundles/jqueryval")
<script>
$(document).ready(function () {
$("#submiter").click(function () {
jQuery.support.cors = true;
var person = new Object();
person.name = "Sourav";
person.surname = "Kayal";
$.ajax({
url: '/api/ProfesorCurso/test',
type: 'PUT',
dataType: 'json',
data: person,
success: function (data) {
console.log(data);
return false;
},
error: function (x, y, z) {
alert('error al postear');
return false;
}
});
});
});
</script>
}
What can I do to prevent ajax to call my api when clicking my form button, if there are Jquery validation errors?
thanks
You should be handling the .submit() event of the form, and then your can check .valid(), and if not cancel the ajax call. Note you should also be cancelling the default submit.
$('#Editcurso').submit(e) {
e.preventDefault(); // prevent the default submit
if (!$(this).valid()) {
return; // exit the function and display the errors
}
....
$.ajax({
....
});
}
As a side note, there is no point adding new { id="titulo" } etc - the HtmlHelper methods that generate form controls already add an id attribute based on the property name
I can't seem to get the Validation error messages to show under the input model fields on the View.
The [Required] tag above Description input makes the ModelState Invalid, but doesn't stop the submission. I have to catch it with checking the Model State. Am I missing some .js files? I dont' have any examples to doublecheck this.
Here is my model (notice I have only one [Required] for now):
public partial class Requests
{
public int RequestID { get; set; }
public string NickName { get; set; }
public Nullable<double> Lat { get; set; }
public Nullable<double> Lng { get; set; }
public string ZipCode { get; set; }
[Required(ErrorMessage = "Description of what you need is missing.")]
public string Description { get; set; }
public System.DateTime DateCreated { get; set; }
}
Here is my View where the Description input needs input.
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.Description, new { htmlAttributes = new { #class = "form-control", #rows = "20", #cols = "200" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
Here is my controller ActionResult (skinnied down)
if (ModelState.IsValid)
{
//THIS ALL WORKS IF Description HAS INPUT
}
else
{
TempData["Saved"] = "Nothing saved yet. Look for reason.";
return RedirectToAction("StoreRequests", new { lat = requests.Lat, lng = requests.Lng });
}
On ModelState failure the user is directed to the correct View and TempData shows that nothing was saved. However, there is no error message on the View below the offending input, no ValidationSummary at the top of the view, and submission is not stopped on input mistake.
#if(TempData["Saved"] != null)
{
<span style="color: red;">#TempData["Saved"].ToString()</span>
}
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
In order to get client side validation (and therefore prevent the form being submitted if its invalid), you need to include the following scripts in you view (or layout).
jquery-{version}.js
jquery.validate.js
jquer.validate.unobtrusive.js
If you have the default bundles set up by VS when you create a new project, you can simply add the following to the view
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
In addition, you should not be redirecting if ModelState is invalid, but rather returning the current view, which will display any validation errors even if the user has disabled javascript. By redirecting, your lose current ModelState so no validation errors will be displayed in the view your redirecting to, not to mention that any data the user previously filled (except the 2 parameters your passing) will be lost.
public ActionResult Edit (Requests model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// save you data and redirect
}
Include the following necessary scripts directly in your .cshtml file.
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
On Ajax call from Angular controller, i am passing a complex object as data. On MVC controller object has all null values.
I have MVC view as given below, which will be the boiler plate for Register customer View.
<div data-ng-app="customer" id="customer" data-ng-controller="rootViewModel">
<h2>{{ pageHeading }}</h2>
<hr />
<form id="formElement">
<div ng-view></div>
</form>
Using AngularJS, I will be loading the register customer view, mark of register customer view given below. I have register customer function tied to button using ng-click directive.
<fieldset class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-3">Company Name</label>
<div class="col-sm-4">
<input class="form-control inputfieldValidation" ng-model="customer.Name" type="text" placeholder="Full company name" required autofocus />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3">PAN</label>
<div class="col-sm-4">
<input class="form-control" ng-model="customer.Pan" type="text">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3">TIN</label>
<div class="col-sm-4">
<input class="form-control inputfieldValidation" ng-model="customer.Tin" type="text" required />
</div>
</div>
<button class="btn btn-primary proceedNext" id="registerCompany" ng-click="registerCompany(customer)">Register Customer</button>
</fieldset>
I have angular controller, which has function called registerCustomer() that will be called on click of register customer. I have an ajax call inside that function as given below.
customerModule.controller("CustomerRegistration", function ($scope) {
var initialize = function () {
}
$scope.registerCompany = function (customer) {
$.ajax({
url: 'Home/RegisterCompany',//make sure url exist
data: JSON.stringify({company: customer}),//pass data to action
type:'POST',
success: function (data) {
alert(JSON.stringify(data));
//window.location.href = '#Url.Action("Order")'; //redirect
}
});
}
initialize();
});
On MVC, i have a model called Company as given below.
public class Company
{
public string Name;
public string Pan;
public string Tin;
}
and my MVC controller look as
[HttpPost]
public JsonResult RegisterCompany(Company company)
{
//Do something
return null;
}
Always I have null object on MVC controller, please help me if am missing anything. Thanks in advance
EDIT: It looks like you need a view model in mvc or a modification to your post:
public class CompanyViewModel {
public Company company { get; set; }
}
Or use data: JSON.stringify(customer) instead of data: JSON.stringify({ company: customer })
Here is a working example from a website we are developing. It uses Riot.js instead of angular, but the concepts will be similar.
See also http://www.abeautifulsite.net/postjson-for-jquery/
$.getJSON(self.baseUrl + "/SaveApplicant", $('form.#applicant').serialize(), function (response) {
if (response.errorMessage) {
RiotControl.trigger('error_message', response.errorMessage);
return;
} else {
self.packageQuote.applicant = response;
}
RiotControl.trigger("continue","applicant");
});
Or using post, per the link above
$.post(self.baseUrl + "/SaveApplicant", $('form.#applicant').serialize(), function (response) {
if (response.errorMessage) {
RiotControl.trigger('error_message', response.errorMessage);
return;
} else {
self.packageQuote.census = response;
}
RiotControl.trigger("continue","applicant");
},'json');
There is a bit more involved on the MVC side of things, to send back a json response with lower case property name prefixes:
public ActionResult SaveApplicant(Applicant model)
{
if (ModelState.IsValid)
{
var applicant = DbContext.Applicants.FirstOrDefault(row => row.Id == model.Id);
if (applicant == null) {
DbContext.Applicants.Add(model);
} else {
applicant.Clone(model); // implement as needed or use entity state modified.
}
DbContext.SaveChanges();
return FormattedJsonResult(applicant);
}
return ModelErrors();
}
public ActionResult FormattedJsonResult(object model)
{
var camelCaseFormatter = new JsonSerializerSettings();
camelCaseFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
var result = JsonConvert.SerializeObject(model, camelCaseFormatter);
return Content(result, "application/json");
}
public ActionResult ModelErrors()
{
return FormattedJsonResult(
new
{
errorMessage =
String.Join("\n",
ModelState.Values.SelectMany(value => value.Errors).Select(error => error.ErrorMessage))
});
return View();
}
I have JS function that is basically
<script type="text/javascript">
function doSomething() {
var s = 'some data'
return s; }
</script>
and
#using (Html.BeginForm(new { data_to_send = x))
{
//some form controls that are sent to controller via model
}
Is it possible, and how, to assign value returned by doSomething function to x variable in form?
I don't need x in my model, because it won't go to database. It's just some additional info from user, how to manipulate data in model before saving to database.
edit: Controller action is
public actionresult MyController(string data_to_Send, model) {}
In the View:
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.X1)
#Html.HiddenFor(model => model.X2)
}
In the Model:
public class YourModel
{
public string X1 { get; set; }
public string X2 { get; set; }
}
In the Controller:
[HttpPost]
public ActionResult Index(YourModel model)
{
string x1 = model.X1;
string x2 = model.X2;
return View(model);
}
The form has to be posted in order to do what you are looking for.
You can post the model along with PostedDateValue
#using (Html.BeginForm("ActionMethod", "Controller", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-field required">
<label for="Posted Data">Posted Data</label>
<input id="txtPostedData" name="PostedDateValue" >
<input type="submit" class="gradient" value="SUBMIT" />
</div>
}
)
Controller
public ActionResult ActionMethod(string PostedDateValue)
{
}