Displaying nested comments in MVC 3 blog - c#

I am making a Blog using MVC 3, Razor and Entity Framework. I am now working on the Comment section.
I am using the following table for comments.
Here I am using the 'CommentParent' column and setting it a value of an another 'CommentID' if a user is replying to a comment, else I have set a value of null.
Problem
I am using the following code to display comments,
#foreach (var comment in Model.Comments)
{
<div>
#comment.CommentContent
</div>
<br />
}
I am not sure how to display the "replyTo" comments as shown in the image below...
Please can anyone guide me as how this can be done...

First You will have to change your Model Class, Lets suppose your model class is :
public class CommentsModel
{
Public Int64 CommentId {get;set;}
....
....
//Introduce a new property in it as:
Public CommentsModel[] ChildComments {get;set;}
}
This new property will hold the child comments of a specific comment up to N Level. Than in your View you can do it like:
#foreach (var comment in Model.Comments)
{
<div>
#comment.CommentContent
</div>
<br />
#if(comment.ChildComments.Length > 0)
{
// Display Level 1 Comments and so on and so far
}
}
You can manage the lookout of comments by using Css Class on Divs.

try this:
private void CreateComments(int ? postId, int ? cid)
{
int? id = cid;
var replies = new List<Comment>();
if (postId.HasValue())
{
var BlogPost = context.Posts.Single(p=>p.Id == postId.Value);
replies = BlogPost.Comments.Where(c=>c.CommentParent == null);
}
else
{
replies = context.Comments.Where(c=>c.CommentParent == id);
}
int level = 0;
Comment tmp = new Comment();
foreach (Comment reply in replies)
{
tmp = reply;
while(tmp.CommentParent != null){
level++;
tmp = context.Comments.Single(c=>c.Id == tmp.CommentParent);
}
//logic for creating your html tag
//you can use "level" to leave appropriate indent back to your comment.
CreateComments(null,reply.id);
}
}
Edit:
you can even determine your current level like i did inside foreach loop.
i hope this could help.

Related

EntityFramework error when trigger SaveChangesAsync()

Got an error stated
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
when I trigger SaveChangesAsync() function. See my code below:
using (var context = new CommonDBContext()) {
var bbrs = await context.Table1
.ToListAsync();
var lastIndexToRemove = pimc.Result.IndexOf("UIX/");
if (lastIndexToRemove > -1)
{
bbrPimcStr = pimc.Result.Remove(0, lastIndexToRemove);
}
foreach (var bbr in bbrs) {
bbr.XBBR = xbbrStr;
bbr.LastUpdated = DateTime.Now;
bbr.LastUpdatedBy = userId;
if (!pimc.HasError)
{
var graveDKI = context.graveDKIStore
.Where(x => x.RefId == bbr.Id)
.FirstOrDefault();
if (graveDKI != null)
graveDKI.GraveDKI = bbrPimcStr ;
else
context.graveDKIStore.Add(new graveDKIStore
{
Id = Guid.NewGuid(),
GraveDKI = bbrPimcStr ,
RefId = bbr.Id,
MsgType = "PPIXFFT"
});
}
}
return await context.SaveChangesAsync(); // Got issue here
Can someone tell me whats wrong with my code? thanks.
Update: Added exception stack.
I fixed the issue by checking the length of the character, it might be different errors base on what data annotation or validator annotation that you placed on your object. To double check if your validations are correct, you can check through exception stack under EntityValidationErrors to get more in-depth information about it, see image below.
public class GraveDKIStore {
...
[MaxLength(5)] // The issue is here so I changed it to 10.
public string MsgType { get; set; }
...
}
P.S. thanks to Roman Doskoch for a very helpful advice.

Need to get value from DropDownListFor asp.net mvc

I have combobox in view and I need to get select value in combobox.
Code View:
#Html.DropDownListFor(model => model.servicesModel, (SelectList)ViewBag.serviceNames, new { #id = "listNames" })
Code action that added values in combobox(I know, I missed the symbol in database when created table):
var servicesDetails = dbModel.SERVICES.ToList();
ViewBag.serviceNames = new SelectList(servicesDetails, "iIdSevices", "vName");
I have form, press button and after that thanks to #using (Html.BeginForm("SendApplication", "Home", FormMethod.Post)) I send data to My actionResult.
My ActionResult:
[HttpPost]
public ActionResult SendApplication(App_AppTemp_Serv_PersInfModel appFile, int iIdServices)
{
int iIdService = 0;
var serviceDetails = dbModel.SERVICES.Where(x => x.iIdSevices == iIdServices).FirstOrDefault();
iIdService = serviceDetails.iIdSevices;
if (bFile == true)
{
appFile.appModel.vFile = "Приклепленные файлы имеются";
}
else
{
appFile.appModel.vFile = "Приклепленных файлов нет";
}
appFile.appModel.vDate = Convert.ToString(DateTime.Now);
try
{
dbModel.APPLICATIONS.Add(appFile.appModel);
dbModel.SaveChanges();
ModelState.Clear();
}
catch (Exception exc)
{
ViewBag.sErrorMessage = exc.Message;
}
return View("~/Views/Home/ProblemForm.cshtml", appFile);
}
But I can't to get the data from combobox, I don't know how?! Maybe use class and get class value, anyone have a idea for this?
Hi you can get the data from dropdownlist using the name of that control. It seems that in your example model.servicesModel will be the name of dropdownlist. so in your controller get data using that property .
for ex: Assuming App_AppTemp_Serv_PersInfModel is your model, if no, change it accordingly
[HttpPost]
public ActionResult SendApplication(App_AppTemp_Serv_PersInfModel appFile, int iIdServices)
{
//dropdownlist selected value
string selectedvalue = appFile.servicesModel
//other code
}
Hope it was helpful
Thanks
Karthik

ASP .NET MVC overriding when edit while multiple records are opened at once in different tabs-

My custom MVC web application has an overriding problem. I have custom edit page and im edditing university teachers, so they all have a profile picture. This is my edit controller which loads the view.
public ActionResult Edit(int? id)
{
if (cf.CheckDBConnection() != true)
{
return View("~/Views/Error/NoDBConnection.cshtml");
}
if (checksession.CheckSessionState() != 1)
{
return View("~/Views/Error/NotAdmin.cshtml");
}
if (id == null)
{
return View("~/Views/Error/BadRequest.cshtml");
}
var disciplina = db.tblDisciplines.ToList();
ViewBag.disciplina = disciplina;
var specialies = db.tblSpecialities.ToList();
ViewBag.specialty = specialies;
var Ischecked = db.tblTeachersDisciplines.Where(p => p.TeacherID == id).Select(p => p.DisciplineID).ToArray();
ViewBag.Checked = Ischecked;
tblTeacher tblTeacher = db.tblTeachers.Find(id);
var IscheckedSpec = db.tblTeachersSpecialities.Where(p => p.TeacherID == tblTeacher.ID).Select(p => p.SpecialityID).ToArray();
ViewBag.CheckedSpec = IscheckedSpec;
TempData["Photo"] = tblTeacher.ProfilePicture;
if (tblTeacher == null)
{
return View("~/Views/Error/NotFound.cshtml");
}
var department = tblTeacher.TDepartment;
ViewBag.department = department;
return View(tblTeacher);
}
This is the controller that runs after clicking "save"
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,FirstName,SecondName,Title,PersonalCabinet,Laboratory,TelNum,Email,VisitingHours,PersonalInterests,TDepartment,ProfilePicture")] tblTeacher tblTeacher, HttpPostedFileBase file, int[] discipline, int[] specialty, string department)
{
var disciplina = db.tblDisciplines.ToList();
ViewBag.disciplina = disciplina;
var specialies = db.tblSpecialities.ToList();
ViewBag.specialty = specialies;
var Ischecked = db.tblTeachersDisciplines.Where(p => p.TeacherID == tblTeacher.ID).Select(p => p.DisciplineID).ToArray();
ViewBag.Checked = Ischecked;
var IscheckedSpec = db.tblTeachersSpecialities.Where(p => p.TeacherID == tblTeacher.ID).Select(p => p.SpecialityID).ToArray();
ViewBag.CheckedSpec = IscheckedSpec;
tblTeacher.TDepartment = department;
if (department == null || department == "")
{
ModelState.AddModelError("", "Изберете факултет");
return View(tblTeacher);
}
if (!ModelState.IsValid)
{
return View(tblTeacher);
}
if (discipline == null)
{
ModelState.AddModelError(string.Empty, "Моля, изберете дисциплини");
return View(tblTeacher);
}
if (specialty == null)
{
ModelState.AddModelError(string.Empty, "Моля, изберете специалност");
return View(tblTeacher);
}
try
{
var _photo = TempData["Photo"];
if (file != null)
{
if (file.ContentLength > 0 && file.ContentLength < 1000000 && file.ContentType == "image/jpeg")
{
byte[] imageBytes = null;
BinaryReader reader = new BinaryReader(file.InputStream);
imageBytes = reader.ReadBytes((int)file.ContentLength);
_photo = imageBytes;
}
else
{
ModelState.AddModelError(string.Empty, "Профилната снимка е задължителна и трябва да отговаря на описаните условия!");
return View(tblTeacher);
}
}
tblTeacher.ProfilePicture = (byte[])_photo;
db.Entry(tblTeacher).State = EntityState.Modified;
db.tblTeachersDisciplines.Where(p => p.TeacherID == tblTeacher.ID).ToList().ForEach(p => db.tblTeachersDisciplines.Remove(p));
db.tblTeachersSpecialities.Where(p => p.TeacherID == tblTeacher.ID).ToList().ForEach(p => db.tblTeachersSpecialities.Remove(p));
db.SaveChanges();
for (int i = 0; i < discipline.Length; i++)
{
using (RSEntities entities = new RSEntities())
{
tblTeachersDiscipline TD = new tblTeachersDiscipline
{
TeacherID = tblTeacher.ID,
DisciplineID = discipline[i]
};
entities.tblTeachersDisciplines.Add(TD);
entities.SaveChanges();
}
}
for (int i = 0; i < specialty.Length; i++)
{
using (RSEntities entities = new RSEntities())
{
tblTeachersSpeciality TS = new tblTeachersSpeciality
{
TeacherID = tblTeacher.ID,
SpecialityID = specialty[i],
};
entities.tblTeachersSpecialities.Add(TS);
entities.SaveChanges();
}
}
return RedirectToAction("Index");
}
catch (Exception ex)
{
DateTime currentTime = DateTime.Now;
string _error = ex.ToString();
_error = currentTime + " Exception: " + _error;
SendMailOnErrorService mail = new SendMailOnErrorService();
mail.Sendemail(_error);
return View("~/Views/Error/DataBaseError.cshtml");
}
}
The problem seems to occur in this current scenario:
When i open many "Edit" tabs and i save all of them, they all change their profile picture with the one from the last tab opened.
I reckon the problem comes fromTempData["Photo"] = tblTeacher.ProfilePicture;
as it probably takes the picture from the last tab opened and then when I save a tab it applies it to the current teacher profile.
I use TempData["Photo"] = tblTeacher.ProfilePicture; because if I dont, when I edit-save a profile it erases the profilepicture from the database as it comes as null from the view and the controller on its behalf inserts null in the column from the DB.
One of the solutions may be not using TempData at all but what I want to know is why the problem occurs and how it can be solved while still using TempData
PS - I've done some testing and its 100% sure the problem is with TempData
The key string you are using for for TempData is "Photo". The value for returned from TempData for key "Photo" is whatever you last set it to in your HttpGet Edit method. If you have multiple Edit tabs open, the value for TempData["Photo"] will be whatever you last set it to for the last Edit tab open.
If you want to use TempData for each open Edit tab you would need a unique key for each Edit tab like so:
Edit tab 1: TempData["EditTab1_Photo"]
Edit tab 2: TempData["EditTab2_Photo"]
And so on.
And a unique TempData key for each Edit View request is not easy to do, you will have to generate a unique TempData key for each HTTP request and somehow know which key to use in the HttpPost Edit HTTP requests. Challenging and overly complex solution this is.
You do not have a ViewModel for your View and that is what you need, you should stop using TempData right away, see below for what TempData is used for.
The way to solve this problem is a standard ViewModel, an essential core tenant of how MVC data sharing is done between a View and a Controller. A Teacher ViewModel, which will have a byte Photo {get;set;} property among other properties that relate, mostly 1 to 1 in type and name as your tblTeacher entity,thus a unique instance of that Teacher ViewModel will be what is passed back and forth for each open Edit tab.
Currently you are sending the data Entity (tblTeacher) directly to the View which is not ever correct in a MVC design pattern. Your View should not depend on a persistence (database) Entity structure/representation, a structure which will change in the future and when that happens, it should not break your View, your View should depend on a ViewModel which translates your Entity into a structure specific to the View, the controller has the responsibility of translating/mapping the structure of the Entity and the ViewModel back and forth between HTTP requests.
A quote and article for you of what TempData is used for:
"TempData, on the other hand, is geared specifically for working with data on HTTP redirects, so remember to be cautious when using TempData."
http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp-net-mvc-3-applications/

Create Hyperlinks from controller in asp.net MVC

I have a controller, which creates breadcrumbs as follows:
Software > Windows 7 > Outlook 2007
The code to create this is:
ViewBag.breadcrumbs = string.Join(" > ", cbh.Select(i => i.Title));
Is there a straightforward way of making the breadcrumbs hyperlinks, which would point to (i.ParentID) ie:
Software -> forum/index/12
Windows 7 -> forum/index/19
Outlook 2007 -> forum/index/23
Or should I just loop through cbh and manually build <a href=...> strings, and pass those to the view?
Thank you,
Mark
Your best bet is to put the required items into the model then loop through them.
Try something like this:
Model
public class Model
{
public struct BreadCrumb
{
public string Title;
public string Url;
}
public List<BreadCrumb> Breadcrumbs { get; set; }
}
View
#{ int index = 0; }
#foreach(var crumb in this.Model.Breadcrumbs)
{
#(crumb.Title)
if(index < this.Model.Breadcrumbs.Count - 1)
{
<span>></span>
}
index++;
}
Yes, you should build your breadcrumb links in the view. If it helps, you can create a BreadCrumbModel class (if you don't already have one).
ViewBag.breadcrumbs = cbh.Select(i => new BreadCrumbModel()
{
Id = i.Id,
Title = i.Title
});
#{
var printSeparator = false;
}
#foreach(BreadCrumbModel bc in ViewBag.breadcrumbs)
{
#if(printSeparator)
{
<span class="breadcrumb-separator"> > </span>
}
<span class="breadcrumb">
#Html.ActionLink(bc.Title, "index", "forum", new { id = bc.Id });
</span>
#{
printSeparator = true;
}
}
If you want to have breadcrumbs between different controllers and actions (not just forum / index), then add those as properties of your BreadCrumbModel.

Looping rows of entitydatasource

First off.. I am new to asp.net and EF.
I have an EntityDatsource on my page I would like to loop through each row in the result set.
My goal is to dynamically build a page based on the values in the result set. Then to post the information back after it is edited by the user. My plan was to iterate each row on the page_load event. Currently I just have p-code in the area I would like to make this happen. The p-code is as follows
// foreach (DataRow row in AvailableDeviceConfigDataSource.enti Rows)
// {
// if sectionHeading <> lastSectionHeading
// {
// lastSectionHeading = sectionHeading
// AddSettingsSection(sectionHeading)
// }
// AddRowObjects
// }
Any guidance would be much appreciated.
In case anybody comes across this and is interested, I did solve my issue a while ago and figured I should post my answer for the benefit of others....
using (var context = new MyEntities())
{
string lastSectionHeading = "";
bool isFirstHeading = true;
var dynamicPageItems = context.view_dynamicPageItems;
foreach (var item in dynamicPageItems)
{
if (item.IsActive == 1)
{
if (!lastSectionHeading.Equals(item.CategoryId))
{
if (!isFirstHeading)
CloseSection();
lastSectionHeading = item.CategoryId;
AddSettingsSection(item.CategoryDescription);
isFirstHeading = false;
}
AddControl( item.DataType );
}
}
}

Categories

Resources