I want to insert data using partial view for this action method which I have mentioned below.
The problem is that when I submit the Form it doesn't gave me any response.
What can I do with that post the comments and redirect to this page when comment is post?
And my partial view is located in a shared folder.
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Comments([Bind(Include = "CommentId,UserComments,UserId")] Comment comment)
{
if (ModelState.IsValid)
{
db.Comments.Add(comment);
db.SaveChanges();
return Json(comment, JsonRequestBehavior.AllowGet);
}
ViewBag.UserId = new SelectList(db.UserAccounts, "UserId", "FirstName", comment.UserId);
return Json(JsonRequestBehavior.AllowGet);
}
Rendering partial view in layout.
#Html.Partial("_Comments", new OnlineTaxiReservationSystem.Models.Comment())
and the partial view is here:
#model OnlineTaxiReservationSystem.Models.Comment
<script type="text/javascript">
$(document).on('click', '.btnSubmit', function () {
$.ajax({
url: '#Url.Action("Comments", "Home")',
cache: false,
async: true,
data: {
//put the data that you want to save from the partial here
UserId: $('#userId').val(),
UserComments: $('#content').val()
},
success: function (_result) {
window.location.href = "Home/Index";
}
});
});
#if (Session["user"] != null)
{
using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Your Feedback</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group" style="margin-left: 9%">
#Html.LabelFor(model => model.UserId, "User Name", htmlAttributes: new { #class = "control-label col-md-2" })
#*#Html.Label(Session["UserName"].ToString(), htmlAttributes: new { #class = "control-label label-primary col-md-1" })*#
<div class="col-md-4">
#Html.Editor("UserId", null, new { htmlAttributes = new { #class = "form-control", #id = "userId" } })
#Html.ValidationMessageFor(model => model.UserId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserComments, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-lg-12">
#Html.TextAreaFor(model => model.UserComments, new { htmlAttributes = new { #class = "form-control", #id = "content"} })
#Html.ValidationMessageFor(model => model.UserComments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-1 col-md-10">
<input type="submit" value="Submit" id="btnSubmit" class="btn btn-primary" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
}
I think you are making a call to the wrong URL:
You need to add e.preventDefault(); if you are not going to submit by button but from javascript instead:
$(document).on('click', '.btnSubmit', function () {
e.preventDefault(); //cancel the default behavior
//do this instead (the ajax call):
$.ajax({
url: '#Url.Action("Comments", "Home")',
cache: false,
async: true,
data: {
//put the data that you want to save from the partial here
UserId: $('#userId').val(),
UserComments: $('#content').val()
},
success: function (_result) {
window.location.href = "Home/Index";
}
});
});
If you can provide the full details of your 404 call, I can be more spesific.
Related
I have this ajax form:
#using (#Ajax.BeginForm("Create", "Comment", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "comments", InsertionMode = InsertionMode.InsertBefore }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.TextAreaFor(model => model.Content, new{#class = "form-control", id = "exampleFormControlTextarea1", rows = "5", width = "100%", placeholder = "Enter a comment here..." })
#Html.ValidationMessageFor(model => model.Content, "", new { #class = "text-danger" })
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
And want to add the whole content after it gets posted to this div:
<div class="comments"></div>
After searching a bit, I know it should be doable with UpdateTargetId and InsertionMode, but I still don't get it. Any help would be appreciated!
I'm new to MVC asp.net jquery ajax and hoping you guys can help me give insight on my problem.
Thank you so much any answer would be helpful.
I'm just having a self exercise that i saw on some online group to help me gain more knowledge on how to implement jquery on asp.net mvc any advice would help.
Controller
public JsonResult AddJob(jobdetail job)
{
using(jQueryAjaxEntities db = new jQueryAjaxEntities())
{
db.jobdetails.Add(job);
db.SaveChanges();
return Json("Success");
}
}
Heres my AddJob view
Whenever I remove the script src it's saving normally, can anyone explain me why is it like that?
<script src="~/Scripts/jquery-3.4.1.min.js"></script>
<script>
$(document).ready(function () {
$("#btnSave").click(function () {
var JobModel = {
TaskName: $("Task_Name").val(),
Description: $("Description").val(),
DateStarted: $("Date_Started").val(),
DateFinished: $("Date_Finished").val(),
Status: $("Status").val()
};
$.ajax({
type: "POST",
url: "/Home/AddJob",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({ job: JobModel }),
success: function (response) {
window.location.href = "/Home/Index"
}
});
});
});
</script>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.JobID)
<div class="form-group">
#Html.LabelFor(model => model.Task_Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Task_Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Task_Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Date_Started, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date_Started, new { htmlAttributes = new { #class = "form-control", #type = "date" } })
#Html.ValidationMessageFor(model => model.Date_Started, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Date_Finished, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date_Finished, new { htmlAttributes = new { #class = "form-control", #type = "date" } })
#Html.ValidationMessageFor(model => model.Date_Finished, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Status, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Status, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Status, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" id="DivSave">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Submit" id="btnSave" class="btn btn-default" />
</div>
</div>
</div>
}
You are probably hitting your AddJob Action twice. First, the btnSave button is clicked, and by the jquery event, you post your data with ajax. Then, your form submits the data to your AddJob Action as well. And a duplicate record is inserted.
You posting your form twice.
1.#(Html.BeginForm()) Post call as button type is submit.
which is working fine and inserting proper data.
2.jQuery AJAX Post Call.
Missing # for getting values of fields.
So, It inserting Null data.
Code:
TaskName: $("Task_Name").val()
It should be:
TaskName: $("#Task_Name").val()
If you made this changes then it will insert data twice.
So, You need to post form once only.
This can be done:
Change Button type sumit to button. This will avoid post call of form begin.
Remove Jquery post code.
I will suggestions Remove AJAX call code post your form using form post only.
This question already has answers here:
How to upload files using ajax to asp.net mvc controller action
(2 answers)
How to append whole set of model to formdata and obtain it in MVC
(4 answers)
Closed 4 years ago.
I've done a little research on this and it always says the same thing, make sure you have enctype for "multipart/form-data" when trying to do an ajax post with a file to an mvc controller. As far as I can tell, I have done that yet still when I run through the debugger, HttpPostedFileBase always returns null. I'm not seeing where I'm missing something probably very obvious.
Here is the razor view form.
#using (Html.BeginForm("Edit", "Story", FormMethod.Post, new { encType = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(x => x.StoryId)
<div class="form-group">
<div class="row">
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Add/Edit cover art to your story</p>
<img class="img-thumbnail" src="~/Imgs/#Model.CoverArt" />
<input type="file" id="file" name="file" class="form-control" />
</div>
</div>
</div>
<div class="col-sm-8"></div>
</div>
</div>
<div class="form-row">
<div class="col-6">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label text-muted" })
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
<div class="col-3">
#Html.LabelFor(x => x.Genre, htmlAttributes: new { #class = "control-label text-muted" })
#Html.DropDownListFor(x => x.Genre, new SelectList(Model.Genres, "Id", "Name"), new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Genre, "", new { #class = "text-danger" })
</div>
<div class="col-3">
#Html.Label("Visibility", htmlAttributes: new { #class = "control-label text-muted" })
<i class="fa fa-question-circle-o" data-toggle="popover" title="What does visibility mean?" data-placement="right" data-content="Visibility determines whether other users can see this story or not. Public means any other user can read, vote, and review the story. You can change this to private, which will hide the story from other users. You, as the author, will be able to see all of your stories - both public and prviate - under your account."></i>
#Html.DropDownListFor(x => x.Visibility, new SelectList(Model.Visibilities, "Id", "Name"), new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Visibility, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-row mt-3">
<div class="col-6">
#Html.Label("Story Type", htmlAttributes: new { #class = "control-label text-muted" })
#Html.DropDownListFor(x => x.StoryType, new SelectList(Model.StoryTypes, "Id", "Name"), new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.StoryType, "", new { #class = "text-danger" })
</div>
<div class="col-6">
#Html.Label("Target Age Range", htmlAttributes: new { #class = "control-label text-muted" })
#Html.DropDownListFor(x => x.StoryAgeRange, new SelectList(Model.StoryAgeRanges, "Id", "Name"), new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.StoryAgeRange, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-row mt-5">
<div class="col-12">
#Html.Label("Write below", htmlAttributes: new { #class = "control-label text-muted" })
#Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Content, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-row mt-3">
<div class="btn-group">
#Html.ActionLink("Cancel", "Index", "Story", null, new { #class = "btn btn-red" })
<input type="button" id="editStoryBtn" value="Edit story" class="btn btn-blue" />
<a class="btn btn-link ml-auto" href="#Url.Action("PublishingRules", "Legal")">Publishing Guidelines</a>
</div>
</div>
}
Here is the javascript for the ajax call (and the function I use to get the filename):
//get the filename of the uploaded file
var fullPath = document.getElementById('file').value;
if (fullPath) {
var startIndex = (fullPath.indexOf('\\') >= 0 ? fullPath.lastIndexOf('\\') : fullPath.lastIndexOf('/'));
var filename = fullPath.substring(startIndex);
if (filename.indexOf('\\') === 0 || filename.indexOf('/') === 0) {
filename = filename.substring(1);
}
}
//create the new story object
var editedStory = {
__RequestVerificationToken: token,
StoryId: storyId,
CoverArt: filename,
Title: $("input[name='Title']").val(),
Content: CKEDITOR.instances.Content.getData(),
Genre: $('#Genre').val(),
Visibility: $('#Visibility').val(),
StoryType: $('#StoryType').val(),
StoryAgeRange: $('#StoryAgeRange').val(),
WordCount: finalWordCount
}
//post the edited story to the controller
$.ajax({
url: "/story/edit/" + storyId,
type: 'POST',
data: editedStory,
success: function (data) {
window.location.href = data.Url;
},
error: function (error) {
console.log("error is " + error);
}
});
And here is the controller.
//POST story/edit/5
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Edit (EditStoryViewModel viewModel, HttpPostedFileBase file)
{
//confirm model state is valid
if (ModelState.IsValid)
{
//find the correct story by the id and include the reference tables
var StoryToEdit = dbContext.Stories.SingleOrDefault(x => x.Id == viewModel.StoryId);
//verify file upload
if (file != null)
{
StoryToEdit.CoverArt = StoryToEdit.Id + Path.GetExtension(file.FileName);
file.SaveAs(Server.MapPath("/Imgs/") + StoryToEdit.CoverArt);
}
StoryToEdit.Title = viewModel.Title;
StoryToEdit.Content = viewModel.Content;
StoryToEdit.GenreId = viewModel.Genre;
StoryToEdit.StoryAgeRangeId = viewModel.StoryAgeRange;
StoryToEdit.StoryTypeId = viewModel.StoryType;
StoryToEdit.VisibilityId = viewModel.Visibility;
StoryToEdit.WordCount = viewModel.WordCount;
StoryToEdit.UpdatedAt = DateTime.Now;
dbContext.Entry(StoryToEdit).State = EntityState.Modified;
dbContext.SaveChanges();
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Details", "Story", new { id = StoryToEdit.Id });
return Json(new { Url = redirectUrl });
}
else
{
return View(viewModel);
}
}
What's going wrong because the file is never being saved (everything else works).
When you want to post multipart form-data using XMLHttpRequest or a wrapper that uses it (like jQuery). You need to create a FormData object and add the files and formdata you want to send to the server. Only then the data is being sent accordingly to the server.
There are already some answers on how to use the FormData object
Sending multipart/formdata with jQuery.ajax
https://www.mkyong.com/jquery/jquery-ajax-submit-a-multipart-form/
I have EDITSTORIES partial view which must post data to UpdateStories action in Stories controller but it doesn't. It doesn't even hit the breakpoint.
#using (Html.BeginForm("UpdateStories", "Stories", FormMethod.Post, new{enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Stories</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.Image, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Image, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Image, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Story, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Story, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Story, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Update" class="btn btn-default" />
</div>
</div>
</div>
}
Action:
[HttpPost]
public ActionResult UpdateStories(Stories st)
{
ViewBag.Grid= bo.GetAllImages();
if (bo.UpdateImages(st))
{
ViewBag.Data = "Updated successfully";
}
else
{
ViewBag.Data = "Update failed";
}
ViewBag.Style = "display:none";
return View("GetStories", st);
}
}
It's inside the GetStories which is the main view. It's been a long day and still, it hasn't been done. Please help me with it.
Update:
Routes:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Stories", action = "AddStories", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "ShowStories",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Stories", action = "ShowStories", id = UrlParameter.Optional }
);
Update:
View: GetStories
#model HimHer.Models.Stories
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (#Html.BeginForm("GetStories", "Stories", FormMethod.Get))
{
#Html.AntiForgeryToken()
<div style="#ViewBag.Style">
#{
Html.RenderPartial("EditStories", Model);
}
</div>
<hr />
var listData = (List<HimHer.Models.Stories>)ViewBag.Grid;
WebGrid wgImages = new WebGrid(listData, rowsPerPage: 20);
#wgImages.GetHtml(tableStyle: "table table-condensed table-bordered table-striped table-responsive",
columns: wgImages.Columns(
wgImages.Column
(columnName: "Image", header: "Image"),
wgImages.Column
(columnName: "Story", header: "Story"),
wgImages.Column
(columnName: "Image", header: "Download", format: (testItem) => Html.ActionLink("Download", "DownloadStories", new { filename = testItem.Image })),
wgImages.Column
(header: "Edit", format: (testitem) => Html.ActionLink("Edit", "EditStories", new { ID = testitem.ID, Story = testitem.Story, Image = testitem.Image, HiddenID = 1 }))
)
);
}
<h2>Index</h2>
You code will generate 2 forms and they are nested!.
<form action="/Stories/GetStories">
<form action="/Stories/UpdateStories">
<input type="submit" />
</form>
</form>
Nested forms are invalid! This is the reason, when you click the submit button from inner form from the partial view, it is submitting to the action method defined for the outer form.
You should not be nesting forms. So move out the call to the RenderPartial outside of your BeginForm call.
Looking at the code you shared,there is no need to have the form tag in the main view as you do not have any form data you have to submit. So simply remove that.
If you absolutely want another form in the main view, make sure that, it is not creating a nested form situation. You can have 2 forms parallel in the same view
#using (#Html.BeginForm("GetStories", "Stories", FormMethod.Get))
{
<!-- Some form elements needed for this form -->
}
#{ Html.RenderPartial("EditStories", Model); }
I have a popup dialog inside the partial view. When a user clicks "Create" button, a popup dialog is shown, inside the popup dialog is a form where user types information and the information is then save into the database. I got everything working and didn't get any errors but the data I typed didn't get saved into the database.
Please help, I am new to programming, Thank you.
Index page:
<li>#Html.Partial("_Create")</li>
In my _Create partial view, I scaffolded the partial view using the Create template
#model test.Models.Question
<li>Create</li>
<div class="dialog-form-create-question" title="Create a question">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-11">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-8">
<input type="submit" value="Submit" class="btn btn-primary"/>
</div>
</div>
</div>
}
</div>
My JQuery scripts for the form dialog nested inside the partial view:
$(document).ready(function () {
$(".dialog-form-create-question").dialog({
autoOpen: false,
height: 510,
width: 800,
modal: true,
draggable: false,
resizable: false
});
$('.create-question').click(function () {
$('.dialog-form-create-question').dialog("open");
});
$('.cancel-button').click(function () {
$('.dialog-form-create-question').dialog("close");
});
});
In my Home controller, I changed the ActionResult Create(from scaffolding) to _Create:
// GET: Home/Create
public ActionResult _Create()
{
return View();
}
// POST: Home/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _Create([Bind(Include = "Id,Title")] Question question)
{
if (ModelState.IsValid)
{
db.Questions.Add(question);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(question);
}
please try changing
#using (Html.BeginForm())
{
}
to
#using (Html.BeginForm("_Create","Home",FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-11">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
<input type="submit" value="submit"/>
</div>
</div>
</div>
}
and see that your debugger strikes to _Create (post) method in your home controller with the values