I have a normal index page where the list of the contents in the database are displayed. I have a create button in my Index which as of now redirects to another page to Create a new item.
First I tried partial Views to get it working but the page still redirected to another page with no layout. Then I tried using Jquery to hide/show div that contains the HTML code for Create. But I could not post the value to the correct Action method.
I am not having all that I have tried so far. I suppose my Index View wouldn't be of great interest.
Index View when using Jquery
<div> Displaying the index View</div>
<div id="Create" style="display:none">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.LsystemFamily.FamilyName, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.LsystemFamily.FamilyName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LsystemFamily.FamilyName, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.LsystemFamily.DescriptionEN, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.LsystemFamily.DescriptionEN, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LsystemFamily.DescriptionEN, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.LsystemFamily.DescriptionDE, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.LsystemFamily.DescriptionDE, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LsystemFamily.DescriptionDE, "", new { #class = "text-danger" })
<input type="submit" value="Create" class="btn btn-default" />
}
Jquery
<script type="text/javascript">
$(document).ready(function () {
$('#btn').click(function () {
$('#Create').toggle();
});
});
</script>
Controller (when returning Partial View)
public ActionResult Create()
{
return View("_Create");
}
Index View when returning Partial View
<div>
Index View
#Html.ActionLink("Create","Create","Controller");
</div>
#Html.Partial("_Create")
In none of the cases I had my Create displaying the way I wanted.
Based on the Answers I have tried to add the partial View and then toggle the div. but i get the following error
An exception of type 'System.InvalidOperationException' occurred in
System.Web.Mvc.dll but was not handled in user code
Additional information: The model item passed into the dictionary is
of type
'System.Data.Entity.Infrastructure.DbQuery`1[TEDALS_Ver01.Models.LsystemFamily]',
but this dictionary requires a model item of type
'TEDALS_Ver01.Models.LsystemFamily'.
Update : Index View
#using (Html.BeginForm())
{
<p>
Search #Html.TextBox("SearchString")
<input type="submit" class="btn btn-default" value="Search" />
</p>
}
<script type="text/javascript">
$(document).ready(function () {
$('#btn').click(function () {
$('#Create').toggle();
});
});
</script>
<table class="table">
<tr>
<th>
Family Name
</th>
<th>
System Count
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td data-toggle="tooltip" title="#item.DescriptionDE" data-placement="right">
#Html.ActionLink(item.FamilyName, "ViewSystems", "LsystemFamilies", new { id = #item.LsystemFamilyID},null)
</td>
<td data-toggle="tooltip" title="Number of Systems in #item.FamilyName" data-placement="right">
#Html.DisplayFor(modelItem => item.LsystemCount)
</td>
<td>
#*#Html.ActionLink("Add System", "Create", "Lsystems", new { id = item.LsystemFamilyID }, null)|*#
#Html.ActionLink("Edit", "Edit", new { id = item.LsystemFamilyID }) |
#Html.ActionLink("Details", "Details", new { id = item.LsystemFamilyID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.LsystemFamilyID })|
</td>
</tr>
}
</table>
<input type="button" id="btn" class="btn btn-default" value="Create">
</div>
<div id="Create" style="display:none">
#Html.Partial("_Create")
</div>
#section Scripts{
<script type="text/javascript">
$(document).ready(function () {
$('#btn').click(function () {
$('#Create').toggle();
});
});
</script>
#Scripts.Render("~/bundles/jqueryval")
}
UPDATE: Create Post method
public ActionResult Create([Bind(Include = "LsystemFamilyID,FamilyName,LsystemCount,DescriptionEN,DescriptionDE,CreatedOn,ModifiedOn,CreatedBy,ModifiedBy")] LsystemFamily lsystemFamily)
{
lsystemFamily.CreatedOn = DateTime.Now;
lsystemFamily.CreatedBy = User.Identity.Name;
lsystemFamily.ModifiedOn = DateTime.Now;
lsystemFamily.ModifiedBy = User.Identity.Name;
lsystemFamily.LsystemCount = 0;
if (ModelState.IsValid)
{
if (db.LsystemFamily.Any(x => x.FamilyName.Equals(lsystemFamily.FamilyName)))
{
ModelState.AddModelError("FamilyName", "Family Name already Exists");
return PartialView("_Create",lsystemFamily);
}
db.LsystemFamily.Add(lsystemFamily);
db.SaveChanges();
return RedirectToAction("Index");
}
return PartialView("_Create",lsystemFamily);
}
What you exactly want to do, I mean if you want to show Create from on a button click then just create a partail view with Layout = null i.e "_Create" ( no need an action for it), now just render this partial view in the div that you are toggling:
<div id="Create" style="display:none">
#Html.Partial("_Create")
</div>
and on the submission of create request if you want to refresh your index page then either you can user Ajax.BeginForm in _create view or you can post it by jquery ajax.
<script type="text/javascript">
$(document).ready(function () {
$('#btn').click(function () {
$('#Create').toggle();
});
});
</script>
You are trying to access #btn by ID, but you set it as class.btn is a class name.So JQuery can't find your button.Do like this
<script type="text/javascript">
$(document).ready(function () {
$('.btn').click(function () {
$('#Create').toggle();
});
});
</script>
Related
This is the code in my partial view i'm using BeginCollectionItem.
<tr>
#using (Html.BeginCollectionItem("QuoteLines"))
{
<td>
#Html.HiddenFor(m => m.QuoteID)
#Html.HiddenFor(m => m.QuoteLineID)
</td>
<td class="visible-lg col-lg-3">
#Html.TextBoxFor(m => m.Group, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Group, "", new { #class = "text-danger" })
</td>
<td class="col-xs-9 col-sm-9 col-md-8 col-lg-5">
#Html.TextAreaFor(m => m.Description, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</td>
<td class="visible-md visible-lg col-md-2 col-lg-2">
#Html.TextBoxFor(m => m.Quantity, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Quantity, "", new { #class = "text-danger" })
</td>
<td class="col-xs-3 col-sm-3 col-md-2 col-lg-2">
#Html.TextBoxFor(m => m.Price, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Price, "", new { #class = "text-danger" })
</td>
<td>
<button type="button" class="delete form-control btn-default" data-id="#model.QuoteLineID">Delete</button>
</td>
}
The important part is the delete button, it has a class referenced by javascript to delete the row. But for some reason it does not execute the code if the row has no data.
<button type="button" class="delete form-control btn-default" data-id="#model.QuoteLineID">Delete</button>
Javascript code:
<script>
var url = '#Url.Action("DeleteQuoteLine")'; // assumes its in the same controller
$('.delete').click(function () {
if (confirm('verwijderen?')) {
var id = $(this).data('id');
var row = $(this).closest('tr');
if (id == 0) { // or if(id == 0) depending if your property is nullable
row.remove(); // the item never existed so no need to call the server
return;
}
$.post(url, { ID: id }, function (response) {
if (response) {
row.remove(); // OK, so remove the row
} else {
// Oops - display and error message?
}
});
}
});
</script>
What do you mean by row has no data? If row has no data, thus there is no numerical ID value stored in data-id, then the reason could be is the post expects there to be an ID of a valid type, but it's null, thus the Action method is throwing an error (which would be caught using ASP.NET error handling... if you are logging those errors, check the log). To verify that, use a networking tool to see if it is making the request to the server, and returning an error response.
Can you please post the action method signature? That would help to see.
Right now, on my page I have a button at the top of one of my views <button type="button" id="show">Find Project</button> that when pressed, renders a partial view (which is a table) at the bottom of the page. My layout is formatted as:
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<!--this is my navbar-->
</div>
<div class="container body-content">
#RenderBody()
</div>
<div class="wrapper">
<!-- TABLE WILL APPEAR HERE -->
</div>
</body>
The javascript that makes the table appear is:
$(document).ready(function() {
$("#show").on("click", function() {
$.ajax({
url: '/Projects/SearchTable',
type: "GET"
}).done(function(partialViewResult) {
$(".wrapper").html(partialViewResult);
$(".wrapper").css('display', 'block');
});
});
});
/Projects/SearchTable is the controller action that renders the partial view:
[HttpGet]
public ActionResult SearchTable()
{
var states = GetAllStates();
var model = new ProjectClearanceApp.Models.ProjectViewModel();
model.States = GetSelectListItems(states);
model.Projects = from m in db.Projects select m;
return PartialView("~/Views/Projects/_ClearedProjects.cshtml", model);
}
The text boxes are dispersed throughout my main view, and all appear in the same format:
<div class="col-md-5 entry-field">
#Html.LabelFor(model => model.Project.FirstNamedInsured, htmlAttributes: new { #class = "control-label" })
#Html.TextBoxFor(model => model.Project.FirstNamedInsured, new { #class = "form-control text-box single-line", maxlength=150 })
#Html.ValidationMessageFor(model => model.Project.FirstNamedInsured, "", new { #class = "text-danger" })
</div>
Except for two dropdowns that are formatted like so:
<div class="col-md-3 address-info">
#Html.LabelFor(m => m.Project.FirstNamedInsuredAddress.State, htmlAttributes: new { #class = "address-label" })
#Html.DropDownListFor(m => m.Project.FirstNamedInsuredAddress.State,
Model.States,
"--",
new { #class = "form-control address-entry" })
#Html.ValidationMessageFor(model => model.Project.FirstNamedInsuredAddress.State, "", new { #class = "text-danger" })
</div>
where Model.States is an enumerable to populate the drop down list with all of the states.
Is it possible to get the data from those textboxes and pass them as data/arguments to the controller for use in the partial view without submitting a form or refreshing the page?
Send the parameter like this:
public ActionResult SearchTable(string firstNamedInsured)
{
//Use the parameter in the model or any where
var states = GetAllStates();
var model = new ProjectClearanceApp.Models.ProjectViewModel();
model.States = GetSelectListItems(states);
model.Projects = from m in db.Projects select m;
return PartialView("~/Views/Projects/_ClearedProjects.cshtml", model);
}
And javascript:
$(document).ready(function () {
$("#show").on("click", function () {
$.ajax({
url: '/Projects/SearchTable?firstNamedInsured=' + $('#' + #Html.IdFor(m => m.Project.FirstNamedInsured)).val(),
type: "GET"
}).done(function (partialViewResult) {
$(".wrapper").html(partialViewResult);
$(".wrapper").css('display', 'block');
});
});
});
I have a form in my webpage that asks for first and last name. When the user submits this form I would like the data to be passed to a function in my controller, where it is used to find the corresponding user in our Active Directory. I want to then return the matching Email address to a Javascript function, when then displays that information on my page. Is this the "correct" way to go about doing this, and if yes, how would I structure a function in my controller to accept form input, and return data to my client side javascript?
What I have so far in my controller:
public SearchResult[] searchAD(String fname, String lname)
{
Func<System.DirectoryServices.ActiveDirectory.Domain> domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain;
System.DirectoryServices.DirectoryEntry root = new DirectoryEntry("LDAP://"+domain);
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchRoot = root;
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = string.Format("(&(objectCategory=person)(objectClass=user)(givenName={0})(sn={1}))", fname, lname);
SearchResult[] results = new SearchResult['a'];
searcher.FindAll().CopyTo(results, 0);
return results;
}
And my form:
#using (Html.BeginForm("searchAD", "AD", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.firstName, "First Name", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.firstName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.firstName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.lastName, "Last Name", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.lastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.lastName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div>
<input type="submit" value="Search" class="btn" />
</div>
</div>
}
You can Store value in TempData and get it on view
public ActionResult searchAD(String fname, String lname)
{
Func<System.DirectoryServices.ActiveDirectory.Domain> domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain;
System.DirectoryServices.DirectoryEntry root = new DirectoryEntry("LDAP://"+domain);
DirectorySearcher searcher = new DirectorySearcher();
searcher.SearchRoot = root;
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = string.Format("(&(objectCategory=person)(objectClass=user)(givenName={0})(sn={1}))", fname, lname);
SearchResult[] results = new SearchResult['a'];
searcher.FindAll().CopyTo(results, 0);
TempData["Result"]=results;
return View("ViewName");
}
In View (Jquery)
$(function(){
if ('#TempData["Result"]' != '')
{
// call your function here and pass TempData Value
}
});
Above is not perfect solution for your posted issue because tempdata or viewbag are not meant for that.If you need to post data again back from control to view then its always make use of #Ajax.BeginForm
#using (Ajax.BeginForm("ActionName", "Controller", new AjaxOptions { OnComplete = "Sucess" }))
in jquery you have to write Success function like below :
function Sucess(arg) {
//arg.data
}
in arg.data you will get that object what you are passing from controller.More ever #Html.BeginForm refreshing your whole page not specific content but with With Ajax.begin form you can manage to reload only those content which is under ajax.begin form.
I know this kind of issue has been solved many times already, however I am unable to get mine fixed based on solutions provided.
I am building a simple library application. There is a feature to add a copy of a book, which uses jQuery to invoke controller actions and return partial views which are then added dynamically to the DOM.
The last dynamically element added is a form with additional details of a created copy. The ajax call is being triggered when a value of a DropDownList (#AuthorBooksDropDown) (also added dynamically) changes.
$('#authorBooksPlaceHolder').on('change', '#AuthorBooksDropDown', function () {
var bookId = $(this).val();
$.get('/Books/AddCopy_RenderDetails/' + bookId, function (data) {
$('#bookDetailsPlaceHolder').html(data);
$('#bookDetailsPlaceHolder').slideDown();
});
$.validator.unobtrusive.parse('#addCopyForm');
});
The call invoked the AddCopy_RenderDetails action get an entity from a DB based on book id, and creates a new copy with certain fields populated.
Controller action:
public PartialViewResult AddCopy_RenderDetails(int id)
{
var book = db.LibraryBooks.Find(id);
var newCopy = new Book()
{
Author = book.Author,
Title = book.Title,
Publisher = book.Publisher,
CollectionId = book.CollectionId,
Collection = book.Collection
};
return PartialView("_AddCopy_Details", newCopy);
}
The view displays remaining fields which need to be populated.
#model CityLibrary.Models.Library.Book
<div class="vertical-separator"></div>
<hr />
#using (Ajax.BeginForm("AddCopy", "Books", new AjaxOptions
{
UpdateTargetId = "bookDetailsPlaceHolder"
}, new { #id = "addCopyForm" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Author)
#Html.HiddenFor(model => model.Title)
#Html.HiddenFor(model => model.CollectionId)
#Html.HiddenFor(model => model.Collection.Name)
#Html.HiddenFor(model => model.Publisher)
<div class="form-group">
#Html.LabelFor(model => model.Collection.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Collection.Name, new { htmlAttributes = new { #class = "form-control", #disabled = "" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ISBN, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ISBN, new { htmlAttributes = new { #class = "form-control", } })
#Html.ValidationMessageFor(model => model.ISBN, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Publisher, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Publisher, new { htmlAttributes = new { #class = "form-control", #disabled = "disabled" } })
#Html.ValidationMessageFor(model => model.Publisher, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.YearPrinted, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.YearPrinted, new { htmlAttributes = new { #class = "form-control", #Value = "" } })
#Html.ValidationMessageFor(model => model.YearPrinted, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-success btn-block" />
</div>
</div>
}
Even though I have $.validator.unobtrusive.parse('#addCopyForm'); invoked when the form is rendered (checked in chrome dev tools), validation still happens on the server side upon pressing a submit button as a POST action is being triggered every time. Not to mention that validation errors do not display upon TABing to next field.
Validation attributes are there in form's inputs:
I also have remote validation which checks whether a entered ISBN is already in the database. Obviously this works on the client side, which in my case simply does not.
Thank you for your time and help.
EDIT:
Well, I've added the following to the end of the view:
<script>
$.validator.unobtrusive.parse('#addCopyForm');
</script>
And it works. I have no idea why triggering it on a function does nothing.
Ajax is async, and your $.validator.unobtrusive.parse('#addCopyForm'); line of code is being called before the html has been added to the DOM. Move it to inside the success callback
$.get('/Books/AddCopy_RenderDetails/' + bookId, function (data) {
$('#bookDetailsPlaceHolder').html(data);
$('#bookDetailsPlaceHolder').slideDown();
$.validator.unobtrusive.parse('#addCopyForm');
});
Try this peace of code
$("form").on("submit", function (e) {
e.preventDefault();
$.validator.unobtrusive.parse($('#addCopyForm')); // here you need define your form id
if ($(this).valid()) // use to validate the form
{
//do ajax call
$.ajax({
type: "Post",
url: "/Books/AddCopy_RenderDetails/" + bookId,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
}
});
}
});
Using MVC/Json/Jquery.
Using form to create a new "group".
Form is on ~Group/Manage, posting form to ~Group/Create
Whilst working on this, returning Json result was working fine, handling in Jquery, no URL redirection.
Now, everytime I run it, it redirects me to ~Group/Create and displays the Json result.
Controller Group/Create
[HttpPost]
public ActionResult Create([Bind(Include="name,description")] GroupModel groupmodel)
{
...
return Json(new { success = true, message = groupmodel.name }, JsonRequestBehavior.AllowGet);
}
Form
<form id="frm_createGroup" action="/Groups/Create" method="post">
<h2>Create Group</h2>
<div class="form-group">
#Html.LabelFor(model => model.name, new { #for = "name" })
#Html.TextBoxFor(model => model.name, new { #class = "form-control", #placeholder = "Group Name" })
#Html.ValidationMessageFor(model => model.name)
</div>
<div class="form-group">
#Html.LabelFor(model => model.description, new { #for = "description" })
#Html.TextBoxFor(model => model.description, new { #class = "form-control", #placeholder = "Group Description" })
#Html.ValidationMessageFor(model => model.description)
</div>
<span id="createGroupMessage"></span>
<button type="submit" class="btn btn-primary pull-right">Create</button>
</form>
Jquery to handle form
$(document).ready(function (){
$('#navGroups').makeActiveMenuItem();
var options = {
success: groupCreateSubmitted
,error: groupCreateError
}
$('#frm_createGroup').ajaxForm(options);
});
function groupCreateSubmitted(responseText, statusText, xhr, $form) {
if (responseText.success)
{
$('#createGroupMessage').html = "Group Created";
}
else
{
$('#createGroupMessage').html = responseText.message;
}
}
To be clear, I don't want URL redirection, I just want the Jquery to catch the return (it was before, have no idea why its changed...)
Thanks!
removed
,error: groupCreateError
working now...form bind was failing.