I want to display an autocomplete textbox in a MVC C# View using jQuery-ui autocomplete, this is the code of my view
#{
ViewBag.Title = "Index";
}
<script src ="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" />
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script type="text/javascript">
$(function () {
$("#SearchString").autocomplete({
source: "/Borrar/autocompletar",
minLength: 1,
select: function (event, ui) {
if (ui.item) {
$("#SearchString").val(ui.item.value);
}
}
});
});
</script>
<div class="container col-md-10 col-md-offset-3">
<h2>Autocompletar</h2>
#using (Html.BeginForm())
{
<p>
Empresa: #Html.TextBox("SearchString")
<input type="submit" value="Search" />
</p>
}
</div>
this is the code of the controller that should populate the textbox
public JsonResult autocompletar(string prefix)
{
List<GFC_Site.ViewModels.EmpresaAutocomplete> listado = new List<GFC_Site.ViewModels.EmpresaAutocomplete>();
ProxyGFC.ServiceGFCClient cliente = new ProxyGFC.ServiceGFCClient();
List<WcfService.Entidades.EmpresaAutocomplete> listadoBase = new List<WcfService.Entidades.EmpresaAutocomplete>();
listadoBase = cliente.Autocompletar(prefix);
foreach (var item in listadoBase)
{
GFC_Site.ViewModels.EmpresaAutocomplete dato = new ViewModels.EmpresaAutocomplete();
dato.empresa = item.empresa;
//dato.np = item.np;
listado.Add(dato);
}
return Json(listado, JsonRequestBehavior.AllowGet);
}
where (GFC_Site.ViewModels.EmpresaAutocomplete) is a class with only one string property (empresa) and (ProxyGFC.ServiceGFCClient cliente) is a connection to a WCF Server, the WCF is the one that connects the application with the database and (List listadoBase) is a class in WCF with two properties(empresa and np).
and this is the method in WCF that retrieve the info that I want to display in the textbox
public List<EmpresaAutocomplete> Autocompletar(string prefix)
{
OdbcCommand cmd = Helper.Commandos.CrearComando();
cmd.CommandText = "select numero_patronal, nombre_empresa from empresas where estado= ? and nombre_empresa like ?";
cmd.Parameters.Add("#estado", OdbcType.VarChar).Value = "1";
cmd.Parameters.AddWithValue("#empresa", prefix + "%");
List<EmpresaAutocomplete> data = new List<EmpresaAutocomplete>();
try
{
cmd.Connection.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
EmpresaAutocomplete datos = new EmpresaAutocomplete();
datos.np = reader["numero_patronal"].ToString();
datos.empresa = reader["nombre_empresa"].ToString();
data.Add(datos);
}
}
catch (Exception ex)
{
throw new ApplicationException("Excepcion :", ex);
}
return data;
}
well, my problem is that the textbox doesn´t show anything, actually it gets frozen
could you please tell me what seems for you to be the problem?
First off, let’s take take a look at autocomplete in action, starting with a text input:
<label for=”somevalue”>Some value:</label><input type=”text” id=”somevalue” name=”somevalue”/>
If we add a reference to the jQuery UI script file and css file, we can add a script block to our view:
<script type=”text/javascript” language=”javascript”>
$(document).ready(function () {
$(‘#somevalue’).autocomplete({
source: ‘#Url.Action(“Autocomplete”)’
});
}) </script>
This script block identifies the text input by id and then invokes the autocomplete function to wire up the autocomplete behaviour for this DOM element. We pass a URL to identify the source of the data. For this post I’ve simply created an ASP.NET MVC action that returns JSON data (shown below). Note that in the view I used Url.Action to look up the URL for this action in the routing table – avoid the temptation to hard-code the URL as this duplicates the routing table and makes it hard to change your routing later.
public ActionResult Autocomplete(string term)
{
var items = new[] {“Apple”, “Pear”, “Banana”, “Pineapple”, “Peach”};
var filteredItems = items.Where(
item => item.IndexOf(term, StringComparison.InvariantCultureIgnoreCase) >= 0
);
return Json(filteredItems, JsonRequestBehavior.AllowGet);
}
https://blogs.msdn.microsoft.com/stuartleeks/2012/04/23/asp-net-mvc-jquery-ui-autocomplete/
Related
I started learning AJAX like this week and I was trying to make a simple voting thingy on page in asp mvc - when you click one button you get message like a popup (in browser) and count increments, when you click second, you get another count decrements, you get the idea.
I wanted to test it's possible to do like voting system (upvotes/downvotes) that will update itself's oount on click without needing to refresh the page.
However, when I click on this buttons, it gets me blank page with the things that return json contains. (picture included at the very bottom of post).
I am most likely missing something obvious, so please bear with me and if you could navigate me where am I wrong, please do.
My Controller:
public IActionResult Privacy()
{
Vote vote = new Vote();
vote.Votes = 0;
return View(vote);
}
[HttpPost]
public ActionResult VoteUp(string plus, string minus)
{
Vote vote = new Vote();
if (plus == null)
{
vote.Votes = vote.Votes -1;
var message = "You voted down";
return Json(new { success = true, message = message }, new Newtonsoft.Json.JsonSerializerSettings());
}
else if ((minus == null))
{
vote.Votes = vote.Votes +1 ;
var messagez = "You voted up";
return Json(new { success = true, message = messagez }, new Newtonsoft.Json.JsonSerializerSettings());
}
else { }
var messagebad = "STH WENT WRONG";
return Json(new { success = true, message = messagebad }, new Newtonsoft.Json.JsonSerializerSettings());
}
My View:
#model JSON_RETURN.Models.Vote
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#{
ViewData["Title"] = "sssss";
}
<form asp-action="VoteUp" asp-controller="Home" method="POST" data-ajax="true">
<div class="form-group"> </div>
<div class="input-group-button">
<button name="plus" class="btn btn-dark" onclick="" value="1" >+</button>
#Model.Votes
<button name="minus" class="btn btn-dark" onclick="" value="-1" >-</button>
</div>
</form>
#section scripts{
<script src="~/lib/ajax/jquery.unobtrusive-ajax.js"></script>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script type="text/javascript">
function SubmitForm(form) {
form.preventDefault();
$.ajax({
type: "POST",
url: "HomeController/VoteUp", //form.action,
data: ('#form'),
success: function (data) {
if (data.success) {
alert(data.message);
} else {
}
},
});
};
</script>
}
My Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace JSON_RETURN.Models
{
public class Vote
{
public int Votes { get; set; }
}
}
And there's the blank page I'm getting every click (message varies ofc):
(https://imgur.com/uVNSmE6)
What you did is just a form submit instead of using ajax. Why it return json string that is because you return json string in your backend code(return Json(new { success = true, message = messagebad }, new Newtonsoft.Json.JsonSerializerSettings());).
I saw you use jquery.unobtrusive-ajax.js in your code, also you create a js function with ajax. Actually, you just need to choose one of the two ways to achieve your requrement.
Here is the correct way of using jquery.unobtrusive-ajax.js :
Note:
1.If you use asp.net core, it contains jquery.js in _Layout.cshtml by default. So when you use #section Scripts{}, no need add the jquery.js again. If your _Layout.cshtml does not contain jquery.js, you need add this js file before jquery.unobtrusive-ajax.js:
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/ajax/jquery.unobtrusive-ajax.js"></script>
2.You need specific data-ajax-update to tell the elements where need to be updated with the AJAX result.
More supported data attributes for jquery.unobtrusive-ajax.js you can refer to here.
View:
#model Vote
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#{
ViewData["Title"] = "sssss";
}
<div id="result"> //add this div...
//add this...
<form asp-action="VoteUp" asp-controller="Home" method="POST" data-ajax-update="#result" data-ajax="true">
<div class="form-group"> </div>
<div class="input-group-button">
<button name="plus" class="btn btn-dark" value="1">+</button>
#Model.Votes
<input hidden asp-for="Votes" /> //add this....
<button name="minus" class="btn btn-dark" value="-1">-</button>
</div>
</form>
</div>
#section scripts{
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ajax-unobtrusive/3.2.6/jquery.unobtrusive-ajax.js" integrity="sha256-v2nySZafnswY87um3ymbg7p9f766IQspC5oqaqZVX2c=" crossorigin="anonymous"></script>
}
Controller:
Note: You can see that I add a hidden input for Votes in form, that is because only input or select type of element can be post to backend. The reason for why I want to get Votes value is because your code always create a new instance for Vote, the value will always plus start with 0.
public IActionResult Privacy()
{
Vote vote = new Vote();
vote.Votes = 0;
return View(vote);
}
[HttpPost]
public ActionResult VoteUp(string plus, string minus)
{
Vote vote = new Vote();
vote.Votes = int.Parse(Request.Form["Votes"]);
if (plus == null)
{
vote.Votes = vote.Votes - 1;
}
else if ((minus == null))
{
vote.Votes = vote.Votes + 1;
}
else { }
return PartialView("Privacy", vote);
}
Result:
Can somebody help in displaying webapi data in angularjs repeat directive in my first Angular application?
I'm getting data from the WEBAPI as expected like below
[{"FLAVOR_ID":"BES","FLAVOR_NAME":"BES"},{"FLAVOR_ID":"BUN","FLAVOR_NAME":"BUN"}]
API Controller:
public class ItemMaintenanceController : ApiController
{
ItemMaintenanceRepository itemRepository;
public ItemMaintenanceController(ItemMaintenanceRepository _itemRepository)
{
itemRepository = _itemRepository;
}
[HttpGet]
public IEnumerable<MA_Flavor> GetAllFlavors()
{
return itemRepository.GetAllFlavors();
}
}
Client.html:
<!DOCTYPE html>
<html>
<head>
<title> Client</title>
<script src="Scripts/angular.js"></script>
<script src="Scripts/angular-resource.js"></script>
<script>
alert("start");
var app = angular.module("myapp", ['ngResource']);
var controller = function ($scope, $resource) { // controller uses $resource, which is part of ngResource
$scope.flavor = {};
$scope.getFlavors = function () {
alert("calling getflvors");
var request = $resource("http://localhost:55762/api/ItemMaintenance/GetAllFlavors?Id=CMN");
$scope.flavor = request.query();
};
////$scope.clear = function () {
//// $scope.flavor = {};
//// $scope.error = "";
////}
$scope.getFlavors();
myapp.controller("ItemMaintenanceController", controller);
</script>
</head>
<body ng-app="contacts">
<div ng-controller="ItemMaintenanceController">
<select ng-model="flavor">
<option ng-repeat="fl in Flavor" value="{{fl.FLAVOR_NAME}}">{{fl.FLAVOR_NAME}}</option>
</select>
<h1>You selected: {{flavor.FLAVOR_NAME}}</h1>
</div>
</body>
</html>
Looks like issue with the names of the ng-controller, ng-module and ng-app. Try to change and hope it will work.
<body ng-app="contacts">
<div ng-controller="ItemMaintenanceController">
<Script>
var app = angular.module('contacts', []);
// To fetch all falvors
app.controller("ItemMaintenanceController", function ($scope, $http) {
.....
...
</script>
I think you're close. based on what you have I think something like this should work:
<select ng-model="selectedFlavorId">
<option ng-repeat="fl in flavor" value="{{fl.FLAVOR_ID}}">{{fl.FLAVOR_NAME}}</option>
</select>
your data is in $scope.flavor and I assume that if you debug it will look like this:
$scope.flavor = [{"FLAVOR_ID":"BES","FLAVOR_NAME":"BES"},{"FLAVOR_ID":"BUN","FLAVOR_NAME":"BUN"}]
you want the id in your value field as that is the bit you need to know which value you selected. the value you see in dropdown should be the name of the flavor.
when you select something, that value will be reflected in the model.
as I chose selectedFlavorId, you will find that populated under $scope.selectedFlavorId. Do not override your API data with the selected value like you've just done.
selectedFlavorId will give you the ID of the item you selected so you need a bit more code after this to get the name of that property from your data array.
There may following issues in your code.
Your angular modules defined as myapp and in ng-app you have used
contacts.
You have to create two different scope variables, one for the flavor
and another is flavors. flavors you need to use under the ng-options
and flavor you have to use for ng-model.
What I understood request.query() will return the resource object,
So have two options to get data from the query. More details about
the resource you can find here
var request = $resource("http://localhost:55762/api/ItemMaintenance/GetAllFlavors?Id=CMN");
Option 1
request.query(function(data) {
$scope.flavor = data;
});
Option 2
request.query().$promise.then(function(data) {
// success
$scope.flavor = data;
}, function(errResponse) {
// fail
});
This is the way I was sending my model to an angular controller scope.
c# Controller:
public class AreaMenuController : RootController
{
// GET: Menu
public PartialViewResult Index()
{
var mod = Modules.Instance.ModuleList.FirstOrDefault(m => m.Prefix.Equals(base.GetArea(), StringComparison.CurrentCultureIgnoreCase));
return PartialView("_AreaMenu", mod.ModuleMenus);
}
}
View cshtml:
#using Nuclei.Models
#model IEnumerable<Nuclei.Models.Menu>
<script type="text/javascript">
#{ var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); }
window.areaMenus = #Html.Raw(serializer.Serialize(Model));
</script>
<script type="text/javascript" src="#Url.Content("~/Scripts/AngularControllers/_AreaMenuController.js")"></script>
<div ng-controller="AreaMenuController as vm" ng-init="vm.initializeController()">
<div id="accordion" ng-class="accordian-menu" style="visibility: visible;">
<ul>
<li ng-repeat="menu in vm.areaMenus">
...
</li>
</ul>
</div>
</div>
Angular Js file:
var NucleiApp = angular.module('NucleiApp');
NucleiApp.controller('AreaMenuController', ['$scope', '$http', '$location', function ($scope, $http, $location) {
"use strict";
var vm = this;
vm.initializeController = function () {
vm.areaMenus = window.areaMenus;
}
}]);
Question 1: Is there a smoother way to send your c# model through to angular other than through global window object?
You can use an $http get from angular, however because this is processed client-side there is always a bit of lag before it gets displayed, because it needs to call the c# controller and get the data. So I'm reserving $http get for updates only.
The other other way I was thinking was to send the view a Json object straight off:
c# controller:
public class AreaMenusController : RootController
{
// GET: Menu
public PartialViewResult Index()
{
return PartialView("_AreaMenu", GetAreaMenus());
}
public JsonResult GetAreaMenus()
{
var mod = Modules.Instance.ModuleList.FirstOrDefault(m => m.Prefix.Equals(base.GetArea(), StringComparison.CurrentCultureIgnoreCase));
return Json(new { areaMenus = mod.ModuleMenus }, JsonRequestBehavior.AllowGet);
}
}
View cshtml:
#using System.Web.Mvc
#model JsonResult
<script type="text/javascript">
window.areaMenus = #Model;
</script>
Question 2: I'm not really sure how to initialize the #model at this point and send it through to the angular file and again, if there is a better option than javascripts global window object... open to suggestions!
We currently do this to bootstrap a set of data that is later updated by a call into a WebAPI.
The reason we do this is we have found cases where the data, when bootstrapped via an API call, was coming back too slowly, which gave a bad experience to our users.
In our razor view:
<html>
<head>
<script>
window.areaMenus = '#Html.Raw(Model.SerializedJsonString)';
</script>
</head>
</html>
Then when our angular app is Run(), we deserialize the data, and use it from there:
var app = angular.module('myApp', ["stuff"])
.run(["menuService", (menuService) => {
// deserialize the json string into my object
var areaMenus = angular.fromJson(window.areaMenus);
// do something with it
menuService.Load(areaMenus);
}]);
This'll get the data available to angular immediately without having to wait for a $http request to complete, which should address your issue.
I am using c# and ASP.NET MVC4 for a web application (with mobile template).
I'm having a problem with my Details view page. (First you select something from Index page and then it goes to Details page) I have put a bing map on the page and the map doesn't load.
First I thought it was something wrong with the map but its not.
I noticed that the url is
http://localhost:2550/Place/Details
of the page. However if I manually put a '1' on the end like so http://localhost:2550/Place/Details/1
then the map loads on the page. I don't understand why this is...
does anyone know why? thanks
my view page for Details:
#model Project.Models.Place
#{ ViewBag.Title = "Details";}
<h2>Place Details</h2>
<fieldset>
<div class="display-label"> Name: #Model.Name</div>
<div class="display-label">Address: #Model.Address</div>
<div class="display-label">Post Code: #Model.PostCode</div>
<div class="display-label"> PhoneNo: #Model.PhoneNo</div>
</fieldset>
<p> #Html.ActionLink("Back to List", "Index")</p>
<body onload="getMap();">
<div id='myMap' style="position:relative; width:400px; height:400px;"></div>
<div>
<input type="button" value="createWalkingRoute" onclick="createDirections();" />
</div>
<div id='directionsItinerary'> </div>
</body>
#section scripts{
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map = null;
var directionsManager;
var directionsErrorEventObj;
var directionsUpdatedEventObj;
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('myMap'), { credentials: 'mykey' });
}
function createDirectionsManager() {
var displayMessage;
if (!directionsManager) {
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
displayMessage = 'Directions Module loaded\n';
displayMessage += 'Directions Manager loaded';
}
alert(displayMessage);
directionsManager.resetDirections();
directionsErrorEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', function (arg) { alert(arg.message) });
directionsUpdatedEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', function () { alert('Directions updated') });
}
function createWalkingRoute() {
if (!directionsManager) { createDirectionsManager(); }
directionsManager.resetDirections();
// Set Route Mode to walking
directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.walking });
var seattleWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Seattle, WA' });
directionsManager.addWaypoint(seattleWaypoint);
var redmondWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Redmond, WA', location: new Microsoft.Maps.Location(47.678561, -122.130993) });
directionsManager.addWaypoint(redmondWaypoint);
// Set the element in which the itinerary will be rendered
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('directionsItinerary') });
alert('Calculating directions...');
directionsManager.calculateDirections();
}
function createDirections() {
if (!directionsManager) {
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: createWalkingRoute });
}
else {
createWalkingRoute();
}
}
</script>
}
my controller action for Details:
public ViewResult Details(int id)
{
ViewBag.events = eventRepository.PlaceEvents(id);
return View(placeRepository.Find(id));
}
Possible cause, may be you haven't written Controller default controller with Zero arguments.
Or you haven't written controller with [HttpPost] attribute
Will be easy if you put code for the controller here.
If you say that the navigation with /1 at the end works but your current url is without the number, your url on the index page is wrong.
Your url is now something like
#Html.ActionLink("Details", "Place")
Change it to something like this:
#Html.ActionLink("Details", "Place", new { id = #Model.Id })
So the problem is that your id isn't given to your details action.
I have a partial view containing an ajax form. This partial view is loaded onto my page via an ajax call. I can edit the fields and submit the form and everything works normally. However, if I reload the form N times, the form will submit N times when the save button is clicked.
here is the code for the partial view....
#model blah blah...
<script src="#Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")"type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript</script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"type="text/javascript"></script>
<div id="modalForm">
#using (Ajax.BeginForm("Edit", "Info", new{id = Model.UserId}, AjaxOptions{OnSuccess = "infoUpdate" }))
{
//FORM FIELDS GO HERE
<input type="submit" value="Save" />
}
</div>
What am I doing wrong that is causing this behavior?
Each time you reload the form, a trigger is placed for submitting the form. Thus you have n submitting, if you reload the form n times.
Try to load the form only once, if it's possible.
You can try to unbind the submit trigger, when you click on your submit button:
<input type="submit" value="Save" onClick="submitForm()" />
var submitForm = function() {
$("#formAddressShipping form").trigger('submit');
$("#formAddressShipping form").unbind('submit');
return false;
};
Just incase someone is still looking for this - the issue can also occur if you have jquery.unobstrusive js referenced multiple times. For me, I had it in layout and partial. The form got submitted 4 times, may be the field count. Removing the js from partial fixed it. Thanks to this thread ASP.NET AJAX.BeginForm sends multiple requests
Moving this jquery.unobtrusive-ajax.js outside partial solved the issue in my case.
I have faced the same issue and solved it as follows. I have a list. From that list, I call New, Update, Delete forms in UI Dialog. Success will close dialog and will return to list and update the UI. Error will show the validation message and dialog will remain the same. The cause is AjaxForm is posting back multiple times in each submit click.
Solution:
//Link click from the list -
$(document).ready(function () {
$("#lnkNewUser").live("click", function (e) {
e.preventDefault();
$('#dialog').empty();
$('#dialog').dialog({
modal: true,
resizable: false,
height: 600,
width: 800,
}).load(this.href, function () {
$('#dialog').dialog('open');
});
});
//Form submit -
$('#frmNewUser').live('submit', function (e) {
e.preventDefault();
$.ajax({
url: this.action,
type: this.method,
data: $('#frmNewUser').serialize(),
success: function (result)
{
debugger;
if (result == 'success') {
$('#dialog').dialog('close');
$('#dialog').empty();
document.location.assign('#Url.Action("Index", "MyList")');
}
else {
$('#dialog').html(result);
}
}
});
return false;
});
The scripts should be in List UI. Not in partial views (New, Update, Delete)
//Partial View -
#model User
#Scripts.Render("~/bundles/jqueryval")
#using (Html.BeginForm("Create", "Test1", FormMethod.Post, new { id = "frmNewUser", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.UserID)
<p>#Html.ValidationMessage("errorMsg")</p>
...
}
//Do not use Ajax.BeginForm
//Controller -
[HttpPost]
public ActionResult Create(User user)
{
if (ModelState.IsValid)
{
try
{
user.CreatedDate = DateTime.Now;
user.CreatedBy = User.Identity.Name;
string result = new UserRepository().CreateUser(user);
if (result != "")
{
throw new Exception(result);
}
return Content("succes");
}
catch (Exception ex)
{
ModelState.AddModelError("errorMsg", ex.Message);
}
}
else
{
ModelState.AddModelError("errorMsg", "Validation errors");
}
return PartialView("_Create", user);
}
Hope someone get help from this. Thanks all for contributions.
Credit to http://forums.asp.net/t/1649162.aspx
Move the jQuery scripts inside the DIV. This seemed to fix the problem.
The tradeoff is that every post will do a get for each script.
My first post, faced the same issue
here is the solution which worked for me..
#using (Html.BeginForm("", "", FormMethod.Post, new { enctype = "multipart/form-data", id = "MyForm" }))
{
//form fields here..
//don't add a button of type 'submit', just plain 'button'
<button type="button" class="btn btn-warning" id="btnSave" onClick="submitForm()">Save</button>
<script type="text/javascript">
var submitForm = function () {
if ($("#"MyForm").valid())
{
//pass the data annotation validations...
//call the controller action passing the form data..
handleSaveEvent($("#MyForm").serialize());
}
return false;
};
<script>
}