ASP.NET MVC3 C# - edit functionality in detail view of a different controller - asp.net-mvc-3

I'm trying to create a forum. I'm trying to have the functionality of 'post edit' in 'thread details'
I have the standard OTB Thread index view, and when you click on 'details' it shows the OTB Thread details, I have added a foreach to display the posts relating to that thread underneath.
I'm now struggling with adding/allowing the posts that are displayed underneath to be edited. Specifically show/hide.
In context, all posts are 'hidden' until an administrator clicks a button to 'show' a post, and vice versa
Thread Controller:
public ViewResult Details(int id)
{
tb_SH_Forum_Threads tb_sh_forum_threads = db.tb_SH_Forum_Threads.Single(t => t.Thread_ID == id);
ViewBag.Private_ID = new SelectList(db.tb_SH_Forum_PrivateDesc, "Private_ID", "Private_Desc");
return View(tb_sh_forum_threads);
}
View:
#model Shareholder_Forum.Models.tb_SH_Forum_Threads
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>tb_SH_Forum_Threads</legend>
<div class="display-label">Thread_Title</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Title)
</div>
<div class="display-label">Thread_Details</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Details)
</div>
<div class="display-label">tb_SH_Forum_Categories</div>
<div class="display-field">
#Html.DisplayFor(model => model.tb_SH_Forum_Categories.Category_Description)
</div>
<div class="display-label">Thread_Date</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Date)
</div>
<div class="display-label">Replies</div>
<div class="display-field">
#Html.DisplayFor(model => model.Replies)
</div>
</fieldset>
#foreach
(var post in Model.tb_SH_Forum_Posts.Where(w => w.Private_ID == 1).OrderBy(o => o.Post_Date))
{
<div class ="post">
<fieldset>
<p class="post_details">At #post.Post_Date By #(post.Anon == true ? "Anonymous" : post.Username)
</p>
#post.Post_Desc
</fieldset>
</div>}
<p>
#Html.ActionLink("Back to List", "Index")|
</p>
I think I need to use RenderAction and/or Partial views, but I don't understand. Any advice, or point me in the right direction where I can learn about this.
As always, very much appreciated.

Not certain I understand what you want, but here's how you could do what I think you're asking.
#foreach (var post in Model.tb_SH_Forum_Posts.Where(w => w.Private_ID == 1).OrderBy(o => o.Post_Date))
{
if(post.IsEditable) //however you're determining if they can edit the post. Alternatively display both this and the else and use javascript to toggle which one you show
{
///...Your old view post code
}
else
{
#Html.RenderPartial("EditPost", new {postdata = post})
}
}
Make a model
public class PostDataViewModel
{
public Post PostData
{
get;
set;
}
}
EditPost.cshtml
#model PostDataViewModel
// The editable form and button to submit to SaveForumPost action
Save it with
public virtual ActionResult SaveForumPost(PostaDavaViewModel model)
{
//... save edits
// either return a redirect to Detail, or if you don't want to refresh the page call this with ajax
}

Related

MVC 4 Updating a partial view from another partial view using Ajax.BeginForm()

I have a comment section set up on one of my pages. The parent view has a partial view which shows the comments for that ID and gives the option to display another partial view to post a comment. When someone post a comment I want the first partial view within the parent to refresh displaying the new comment.
Currently when you click Post Comment, the AddComment method is called and added to the database. I get an error saying that I am passing the wrong type of model to the view. It seems to be trying to pass the return value to my AddComment partial view instead of injecting it into Partent View Div.
Parent View
#model QIEducationWebApp.Models.Course
#{
ViewBag.Title = "Course Details";
}
<h1 class="page-header">#ViewBag.Title</h1>
Javascript is here
.
.
.
<table class="table">
DETAILS HERE
</table>
<ul id="view-options">
<li>#Html.ActionLink("Back to Courses", "Index", "Course")</li>
</ul>
<input type="button" id="View" class="ShowComment" value="Show Comments"/>
<div id="CommentSection"/>
Partial View to view comments
Javascript is here
.
.
.
<div class="CommentSection">
#foreach (var item in Model)
{
<div class="Comment">
<div class="CommentText">
#Html.DisplayFor(modelItem => item.CommentText)
</div>
<div class="CommentSep">
<span class="Commenter">#Html.DisplayFor(modelItem => item.UserName)</span> - <span class="CommentDate">#Html.DisplayFor(modelItem => item.CommentDate)</span>
</div>
</div>
}
<input type="button" id="Post" class="AddComment" value="Add a Comment"/>
<br />
<br />
</div>
<div id="AddComment" />
<br />
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("ViewComments",
new { courseID = #ViewBag.courseID, page }),
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(
new PagedListRenderOptions { MaximumPageNumbersToDisplay = 5, DisplayLinkToFirstPage = PagedListDisplayMode.IfNeeded,
DisplayLinkToLastPage = PagedListDisplayMode.IfNeeded },
new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "CommentSection" }))
Method behind the is partial view
public PartialViewResult ViewComments(int courseID, int? page = 1)
{
ViewBag.courseID = courseID;
var coursecomments = db.CourseComments.Where(cc => cc.CourseID == courseID);
int pageSize = 10;
int pageNumber = (page ?? 1);
return PartialView(coursecomments.OrderByDescending(cc => cc.CommentDate).ToPagedList(pageNumber, pageSize));
}
Partial to Post Comment
Javascript is here
.
.
.
#using (Ajax.BeginForm("AddComment", "CourseComment", new { courseID = #ViewBag.courseID, userName = #User.Identity.Name },
new AjaxOptions { UpdateTargetId = "CommentSection" }))
{
#Html.ValidationSummary(true)
<div class="NewComment">
<div class="editor-field">
#Html.TextAreaFor(model => model.CommentText, new { maxLength = 500 })
#Html.ValidationMessageFor(model => model.CommentText)
</div>
<input type="submit" class="PostComment" value="Post Comment" />
<div id="Counter" class="CommentCounter"/>
</div>
}
Controller method linked to the Post Comment Ajax.BeginForm()
public PartialViewResult AddComment(CourseComment coursecomment, int courseID, String userName)
{
coursecomment.CommentDate = System.DateTime.Now;
coursecomment.CourseID = courseID;
coursecomment.UserName = userName;
if (ModelState.IsValid)
{
db.CourseComments.AddObject(coursecomment);
db.SaveChanges();
}
ViewBag.courseID = courseID;
return ViewComments(courseID);
}
Adding pictures
Details
After selecting View Comments button
After selecting Add Comment
After Posting the the comment I want the list of Comments to refresh displaying the newly added Comment. Like So
For now I have it changed. I wanted to the comments section to be hidden until the show comments was clicked. Then after posting a comment on the comments section was refreshed, but I couldn't get that to work. So just reloading the whole page will refresh the comments section, but make it hidden at that time. I made it so that the comments section shows by default without the option to hide it. So unless anyone can figure out a way to get it to work how I wanted, this works for now.

DataAnnotations on Entity not displaying in View

I have a Supplier Entitiy that contains
ID - int
Status - string
Name - string
CreateDate- datetime
I am using the partial class method to create Data Annotations for the above Entity.as described here
namespace TemplateEx.Models
{
[MetadataType(typeof(SupplierMetadata))]
public partial class Supplier
{
// Note this class has nothing in it. It's just here to add the class-level attribute.
}
public class SupplierMetadata
{
// Name the field the same as EF named the property - "FirstName" for example.
// Also, the type needs to match. Basically just redeclare it.
// Note that this is a field. I think it can be a property too, but fields definitely should work.
[Required]
[Display(Name = "Supplier Name")]
public string Name;
}
}
My defined a controller action as below
public ViewResult Details(int id)
{
Supplier supplier = db.Suppliers1.Single(s => s.ID == id);
return View(supplier);
}
When I create a view for this action and picked the Details scaffolding for the Supplier entity following is what I got as a view
#model TemplateEx.Models.Supplier
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>Supplier</legend>
<div class="display-label">CreateDate</div>
<div class="display-field">
#Html.DisplayFor(model => model.CreateDate)
</div>
<div class="display-label">Status</div>
<div class="display-field">
#Html.DisplayFor(model => model.Status)
</div>
<div class="display-label">Name</div>
<div class="display-field">
#Html.DisplayFor(model => model.Name)
</div>
</fieldset>
<p>
#Html.ActionLink("Edit", "Edit", new { id=Model.ID }) |
#Html.ActionLink("Back to List", "Index")
</p>
Notice how the model.Name has a "Name" label instead of "Supplier Name".What am I doing wrong?
replace
<div class="display-label">Name</div>
with
<div class="display-label">#Html.LabelFor(model => model.Name)</div>
Edit :
For the second question, look here
How can i enforce the scaffolding automatically generated code to display the Label and the EditorFor text field at the same line in my asp.net mvc 3 (specially last answer)

mvc 3 The model item passed into the dictionary is of type A but this dictionary requires a model item of type B

I am getting the following error:
The model item passed into the dictionary is of type '...Models.VideoPostingModel', but this dictionary requires a model item of type '...Models.RegisterModel'.
I am not sure what the issue is because the models match up...
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using stayyolo.Models;
using System.Web.Security;
using System.Data;
...Controllers
{
public class VidsPostingController : Controller
{
private dbEntities db = new dbEntities();
//
// GET: /VidsPosting/
public ActionResult Details(Guid id)
{
Posting posting = db.Postings.Find(id);
if (posting.Image == null)
{
posting.Image = new byte[0];
db.Entry(posting).State = EntityState.Modified;
db.SaveChanges();
}
//convert ENTITY MODEL CLASS TO Model
VideoPostingModel toRet = new VideoPostingModel();
toRet.linkIfVideo = posting.LinkIfVideo;
toRet.PostDate = posting.PostDate;
toRet.Titile = posting.Titile;
toRet.TypeOfPosting = posting.TypeOfPosting;
return View(toRet);
}
}
Model:
public class VideoPostingModel
{
..Variables
public VideoPostingModel()
{
...
}
}
View:
#model ...Models.VideoPostingModel
#{
ViewBag.Title = "Details";
}
<fieldset>
<legend>Posting</legend>
<div class="display-label">
Description</div>
<div class="display-field">
#Html.DisplayFor(model => model.Description)
</div>
<div class="display-label">
Title</div>
<div class="display-field">
#Html.DisplayFor(model => model.Titile)
</div>
<div class="display-label">
Post Date</div>
<div class="display-field">
#Html.DisplayFor(model => model.PostDate)
</div>
<div class="display-label">
Type Of Posting</div>
<div class="display-field">
#Html.DisplayFor(model => model.TypeOfPosting)
</div>
</fieldset>
<div id="youtubePlayerdiv"">
<p style="text-align: justify">
Video!</p>
<iframe id="youtubePlayer" class="youtube-player" type="text/html"
width="640" height="385" src="http://www.youtube.com/embed/<%=Model.LinkIfVideo%>" frameborder="0">
</iframe>
</div>
<!-- end youtubeplayerDiv div -->
I very much appreciate the help in advance, issue occurs right when the website hits the details method of the controller.
The error you are getting implies that somewhere on your view or _Layout you have tried to render another partial like this:
#Html.Partial("~/Views/Account/Register.cshtml")
But this partial requires a different model - RegisterModel. So one possibility is to pass a new instance of this model to the partial when rendering it:
#Html.Partial("~/Views/Account/Register.cshtml", new RegisterModel())

Using #Html.HiddenFor in MVC3

I'm having lots of troubles.
I think that MVC just hates me.
1st. I'm using Linq and the model is automagically generated. I just completed the properties I need with the [Required] tag/directives.
2nd. I have a "Big Model" that joins two of the models.
Like is explained here -> Multiple models in a view
When I try to postback a view with a model that has those properties like nulls, is has the ModelState.isvalid == false. I think that is obvious because I set the [Required] to some of the properties that the model needs.
And here comes the thing that brought me here.
3rd. When I'm trying to use #Html.HiddenFor(...) my page won't postback.
If I use, let's say, 3 HiddenFor, the page does PostBack, but if I use 10 HiddenFor, the page just stand still. It does not go anywhere.
I've tried to do everything that is within my range of knowledge (very limited, I'm really new at MVC).
I've tried to bring to the view those properties and showing them up as if it were a "Detail View". Didn't succeed.
I've tried to set the #HiddenFor(model => model.Client). In the Action is passed as null.
I've tried to use these tons of HiddenFor.
I've tried to pass just an ID in the hidden (ClientID) and retrieve the object from the database, but the ModelState will not "update" its status once inside the action.
Why am I doing this?
I'm doing this because I need the pages to display the "Required Field Message" when a box isn't filled, hence, forbiding the page to postback without the data.
My database is fine, and those fields are "Not null", so, I can just remove the [Required] from the properties, but I would lose the "Required Field Message" (in addition to the PostBack that is the thing that I'm trying to avoid).
If anyone has the answer or an answer or whatever, please, post it... I'm about to shoot my head out xD
Thanks in advance...
PS: Sorry about my english... I know that it's not good (or even regular).
View
#model PruebaMVC.Models.OperacionModel
<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>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Operación de Venta</legend>
#Html.HiddenFor(model => model.INMUEBLE)
#*#Html.HiddenFor(model => model.INMUEBLE.Direccion)*#
#*#Html.HiddenFor(model => model.INMUEBLE.Localidad)*#
#*#Html.HiddenFor(model => model.INMUEBLE.Ciudad)*#
#*#Html.HiddenFor(model => model.INMUEBLE.Caracteristicas)*#
#*#Html.HiddenFor(model => model.INMUEBLE.PrecioVenta)*#
#*#Html.HiddenFor(model => model.INMUEBLE.CLIENTE.IDCliente)*#
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.Nombre, "Nombre del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.Nombre)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.Nombre)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.Apellido, "Apellido del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.Apellido)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.Apellido)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.FechaNacimiento, "Fecha de Nacimiento del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.FechaNacimiento)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.FechaNacimiento)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.DNI, "DNI del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.DNI)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.DNI)
</div>
<div class="editor-label">
#*#Html.LabelFor(model=>model.OPERACION.IDFormaPago, "Forma de Pago")*#
<label for="ComboFP">Forma de Pago</label>
</div>
<div class="editor-field">
<select id="ComboFP" name="SelectFP">
#{
foreach (PruebaMVC.Models.DatosLINQ.FORMA_PAGO item in PruebaMVC.Models.DatosLINQ.OperacionDatos.ListarFormaPago())
{
<option value="#(item.IDFormaDePago)">#(item.TipoPago)</option>
}
}
</select>
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.Comision, "Comisión de la Venta")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.Comision)
#Html.ValidationMessageFor(model => model.OPERACION.Comision)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.Legajo, "Número de Legajo")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.Legajo)
#Html.ValidationMessageFor(model => model.OPERACION.Legajo)
</div>
<p>
<input type="submit" class="formbutton" value="Cargar Venta" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Volver al listado de Inmuebles", "Index")
</div>
Controller
//
// GET: /Inmueble/Sale/5
public ActionResult VentaP(int id)
{
OperacionModel unModeloOperacionCompuesto = new OperacionModel();
unModeloOperacionCompuesto.INMUEBLE = InmuebleDatos.DetallesInmueble(id);
return View(unModeloOperacionCompuesto);
}
//
// POST: /Inmueble/Sale/5
[HttpPost]
public ActionResult VentaP(OperacionModel model, FormCollection collection)
{
try
{
// TODO: Add insert logic here
model.INMUEBLE = InmuebleDatos.DetallesInmueble(model.INMUEBLE.IDInmueble);
CLIENTE clienteComprador = new CLIENTE();
clienteComprador.Nombre = model.OPERACION.CLIENTE1.Nombre;
clienteComprador.Apellido = model.OPERACION.CLIENTE1.Apellido;
clienteComprador.DNI = model.OPERACION.CLIENTE1.DNI;
clienteComprador.FechaNacimiento = model.OPERACION.CLIENTE1.FechaNacimiento;
OPERACION nuevaOperacion = new OPERACION();
int unIDUsuario = UsuarioDatos.IDUsuario(User.Identity.Name);
int unIDFormaPago = Convert.ToInt32(collection["SelectFP"]);
decimal unaComision = model.OPERACION.Comision;
int unLegajo = model.OPERACION.Legajo;
if (ModelState.IsValid)
{
nuevaOperacion.INMUEBLE = model.INMUEBLE;
nuevaOperacion.FechaOperacion = DateTime.Now;
nuevaOperacion.IDUsuario = unIDUsuario;
nuevaOperacion.IDFormaPago = unIDFormaPago;
nuevaOperacion.INMUEBLE.IDEstado = 2;
nuevaOperacion.Monto = model.INMUEBLE.PrecioVenta;
nuevaOperacion.Comision = unaComision;
nuevaOperacion.Legajo = unLegajo;
nuevaOperacion.CLIENTE1 = clienteComprador;
nuevaOperacion.CLIENTE = model.INMUEBLE.CLIENTE;
OperacionDatos.CrearVenta(nuevaOperacion);
return RedirectToAction("Index");
}
else
{
//return View(nuevaOperacion);
return View(model);
}
}
catch
{
return View(model);
}
}
Edit 2:
I'm still touching the code, and when I comment the line of
#Html.HiddenFor(model => model.INMUEBLE.PrecioVenta)
Where "PrecioVenta" is a decimal(18,2), the page does post back... it is obviously still getting a ModelState.isValid == false because I'm having left that value.
What can I do?
Which are the primitive types for the "HiddenFor" will work?
Or is some stuff of the .Net Framework that can't "map" that datatype properly?
I think that the problem is the client side validations and decimals.
When you have a decimal value, it render it as "35,0" in your culture... but the javascript validator doesn't recognice the "," as a decimal coma.
This is a problem I'm having but I've found a post here in stackoverflow about modifying the javascript validator.
Here you can learn how to fix the javascript validator for decimals

How do I validate a model in a JQuery created dialog and Ajax

I am creating a JQuery dialog where I have use data from a Model I want to validate, but the box is just closed, if I then click to open the dialog again I can see the red text indication errors, but it just closed.
function createEditorDialog() {
$('#floatsam_editor').dialog({ bgiframe: true, autoOpen: false, modal: true, width: 512,
buttons: {
'Close': function () { $('#floatsam_editor').dialog('close'); },
'Create': function () {
$('#flotsam_form').submit();
$('#floatsam_editor').dialog('close');
}
}
});
};
So the red text comes at the submit, but is closed right after, even though the validation failed.
Here is part of the ajax beginform that is shown
<div id="floatsam_editor">
#using (Ajax.BeginForm("CreateFlotsam" , "Flotsam", new { }, new AjaxOptions { HttpMethod = "Post", OnSuccess = "systematic_flotsam.successRequest" }, new { Id = "flotsam_form" }))
{
<div>
<fieldset>
<legend>Create Log Entries</legend>
<div >
<span class="editor-label">
#Html.LabelFor(m => m.Received.Date)
</span>
<span class="editor-field">
#Html.TextBoxFor(m => m.Received.Date, new { id = "flotsam_date", #class="datepicker", maxlength="10"})
</span>
<span class="editor-field">
#Html.TextBoxFor(m => m.Received.Hour, new { id = "flotsam_hours", maxlength="2" })
</span>:<span class="editor-field">
#Html.TextBoxFor(m => m.Received.Minute, new { id = "flotsam_minutes", maxlength="2"})
</span>
<span>
#Html.ValidationMessageFor(m => m.Received.Date)
#Html.ValidationMessageFor(m => m.Received.Hour)
#Html.ValidationMessageFor(m => m.Received.Minute)
</span>
</div>
<div>
<div class="editor-label">
#Html.LabelFor(m =>m.Flotsam.Informant)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Flotsam.Informant, new { #class = "flotsam_dialog_editor_field" })
#Html.ValidationMessageFor(m =>m.Flotsam.Informant)
</div>
</div>
Part of my model is here
[DisplayName("Informant:")]
[Required]
public object Informant { get; set; }
[DisplayName("Flotsam Nature:")]
[Required]
public object FlotsamNature { get; set; }
[DisplayName("Position of Loss:")]
[Required]
public object Position { get; set; }
And as seen it has 3 propertys which are required, but again it still closes if I dont enter anything in my ajax form
So how do I make the dialog box not close when model validation fails?
A very important note is that all this is done on one site and on client side, I do not want to reload the page.
Only close the dialog if the form is valid.
if($("#flotsam_form").valid())
{
$('#flotsam_form').submit();
$('#floatsam_editor').dialog('close');
}
This way it dialog will stay open and validation errors will appear
Since this is dyamically HTML content, you'll need to register the HTML that you wanted validated. This blog post should help you out.

Resources