Aug 1, 2011

MVC 3 : Create A Simple Blog Application Pt. 4



It has been a while since my last post on MVC 3. It was quite a hectic few weeks of my life, since there are a lot of task need to be submitted. Finally I manage to steal some time to finish up my tutorial on how to "Create A Simple Blog Application" by using MVC 3. Since my last tutorial, I did manage to write and guide Negative Zero readers until Post Section where the Part 3 tutorial did cover on making new post, list all post and setting ONLY admin can post new articles. For those who misses out three series of "Create A Simple Blog Application", below is the list of past tutorial:
  1. Part 1 : Cover on creating a new project on MVC 3
  2. Part 2 : Cover on creating models for our blog application using LightSpeed.
  3. Part 3 : Cover on creating new post, delete post, edit post and list post(for admin)
  4. Part 4 : Will be covering on displaying single post and comments. Also, will be covering on new comment controller.
Assuming my blog reader has gone through all past tutorials, in this tutorial we will be creating a controller to handle single post view, and controller to handle blog reader submit a new comment. In order to create a blog application, it is a must for our blog to be able to view a single post followed by all comments related to one post at bottom of the page. So to be able to handle this, we will be creating two different controller which we will name as FullPost and Comment. FullPost controller will be handling the dirty work on fetching data from two joined tables (table Post and table Comment). Since we need to fetch data from different table, which data regarding the article will be fetch from table Post while comments will be fetch from table named Comments, we will use joined LINQ. Why join? No reason, it just I can really think of join the tables together so that I could pass the data through return statement.

So, FullPost controller will look like this:
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Web;
   5: using System.Web.Mvc;
   6: using NegativeZero.Models;
   7: using Mindscape.LightSpeed;
   8:  
   9: namespace NegativeZero.Controllers
  10: {
  11:     public class FullPostController : Controller
  12:     {
  13:         //
  14:         // GET: /FullPost/
  15:         LightSpeedContext context = new LightSpeedContext("Development");
  16:         
  17:         [HttpGet]
  18:         public ActionResult Index(int id)
  19:         {
  20:             using (var UnitOfWork = context.CreateUnitOfWork())
  21:             {
  22:                 var NZ = from a in UnitOfWork.Find<Post>()
  23:                          join b in UnitOfWork.Find<Comment>()
  24:                          on a.Id equals b.PostId
  25:                          where a.Id.Equals(id)
  26:                          select new blogModel
  27:                          {
  28:                              postId = a.Id.ToString(),
  29:                              postAuthor=a.Author,
  30:                              postCategories=a.Categories,
  31:                              postTitle=a.Title,
  32:                              postBody=a.Posts,
  33:                              postTag=a.Tag,
  34:                              comId = b.Id.ToString(),
  35:                              comAuthor = b.Author,
  36:                              comEmail=b.Email,
  37:                              comUrl=b.Url,
  38:                              comBody=b.Comments
  39:                          };
  40:                 return View(NZ.ToList());
  41:             }
  42:         }
  43:  
  44:     }
  45: }
Referring code above, on line 26 – we can see that I did bind the data fetch from joined LINQ query on a new model name blogModel. So to use this model, we need to declare the model definition at folder named Models. Create new class inside Models folder, and paste code below:
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Web;
   5:  
   6: namespace NegativeZero.Models
   7: {
   8:     public class blogModel
   9:     {
  10:         public string postId;
  11:         public string postAuthor;
  12:         public string postCategories;
  13:         public string postTitle;
  14:         public string postBody;
  15:         public string postTag;
  16:         public string comId;
  17:         public string comAuthor;
  18:         public string comEmail;
  19:         public string comUrl;
  20:         public string comBody;
  21:         
  22:     }
  23: }
This model will handle and hold all data from table Post and Comment so that we can use 'Strongly-typed view' when we create the View for FullPost later in this tutorial. Once we have prepare this two files, next we need to create the viewing for FullPost controller in view folder. To create the view, just right click on the Index(int id) method and select option Add View. A popup window will be made available to you to set the view configuration. Select strongly-typed view, and select blogModel as Model Class. On Scaffold option, we need to leave it empty since a lot of code in view need to code by hand. Once we have create the view, paste this code in the view by replacing whatever code that is inside default view template.

@model IList<NegativeZero.Models.blogModel>
<script language="javascript">
var popupWindow = null;
function positionedPopup(url, winName, w, h, t, l, scroll) {
settings =
'height=' + h + ',width=' + w + ',top=' + t + ',left=' + l + ',scrollbars=' + scroll + ',resizable=false'
popupWindow = window.open(url, winName, settings)
}
</script>
@{
    string Title = "";
string Id = "";
string Author = "";
string Category = "";
string Tag = "";
string Body = "";
foreach (var post in Model)
{
Title = post.postTitle;
Id = post.postId;
Author = post.postAuthor;
Category = post.postCategories;
Tag = post.postTag;
Body = post.postBody;
}

ViewBag.Title = Title;
}
<h2>@Title</h2>
<p>
Categories : @Category</p>
<p>@Body</p>
<p>
<b>Written by:</b> @Author</p>
<p>
<b>Post Tags:</b> @Tag</p>
<h3>
Comments:</h3>
@{ int commentCount = 0; }
@foreach (var item in Model)
{
commentCount = commentCount + 1;
<div style="width: 800px; border: thin dotted gray; margin: 5px; padding: 10px; font-size: 13px;
margin-left: 20px;">
<p>
<a href="@item.comUrl">@item.comAuthor</a></p>
<p>@item.comBody</p>
<p style="text-align: right;">
#@commentCount</p>
</div>    
}
<div style="width: 800px; border: thin dotted transparent; margin: 5px; padding: 10px;
font-size: 13px; margin-left: 20px;">
<a href="../../Comment/Create/1" onclick="positionedPopup(this.href,'myWindow','500','400','100','200','yes');return false">
Leave Comment</a>
</div>


Above is the code for single post view in razor syntax. I'm using javascript script to handle new user comments form since I like the way blogger handle the popup window when reader click 'Leave Comment' button. The link at the bottom of this page will also behave like blogger comment button. Once user click the link to leave a new comment, a window will popup with new comment form inside. Once the user finish filling the comment form, button submit will close the popup window on success saving new comment into database. Below is the code for Comment controller which will handle comment form and storing new comment.
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Web;
   5: using System.Web.Mvc;
   6: using NegativeZero.Models;
   7: using Mindscape.LightSpeed;
   8:  
   9: namespace NegativeZero.Controllers
  10: {
  11:     public class CommentController : Controller
  12:     {
  13:         //
  14:         // GET: /Comment/
  15:         LightSpeedContext context = new LightSpeedContext("Development");
  16:         [HttpGet]
  17:         public ActionResult Create(int id)
  18:         {
  19:             ViewBag.postId = id;
  20:             return View();
  21:         }
  22:  
  23:         [HttpPost]
  24:         public ActionResult newComment(string PostId, string Author, string Email, string Url, string Comments)
  25:         {
  26:             Comment newEntry = new Comment();
  27:             
  28:             newEntry.PostId = int.Parse(PostId);
  29:             newEntry.Author = Author;
  30:             newEntry.Url = Url;
  31:             newEntry.Email = Email;
  32:             newEntry.Comments = Comments;
  33:             using (var UnitOfWork = context.CreateUnitOfWork())
  34:             {
  35:                 UnitOfWork.Add(newEntry);
  36:                 UnitOfWork.SaveChanges();
  37:                 return View();
  38:             }
  39:         }
  40:  
  41:     }
  42:  
  43:     
  44: }
And the view which will be the form for new comment is attached in below box:

@model NegativeZero.Models.Comment
@{
    Layout = "";
}
<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("newComment","Comment"))
{
@Html.ValidationSummary(true)
<fieldset>
<legend>Leave Comment</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Author)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Author)
@Html.ValidationMessageFor(model => model.Author)
</div>
<div class="editor-label">
@Html.Label("Website")
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Url)
@Html.ValidationMessageFor(model => model.Url)
</div>
<div class="editor-label">
@Html.Label("Email Address")
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Email)
@Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
@Html.Label("Comments")
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Comments, new { style = "width:300px;height:100px;" })
@Html.ValidationMessageFor(model => model.Comments)
@{int PostId = ViewBag.postId;}
            @Html.Hidden("PostId", PostId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>


Once we have finish on Create method view, we need one more piece of code to handle the closure of comment form popup window. To handle this, we create a view named newComment as we named our controller method which process and store the new comment. The one line code is written in the box below:

<script>window.close()</script> 

Once we have all file copied and pasted as requested in this tutorial, we can now try compile our fresh codes to seek if there are any error on the code. By default, there should be no error since I did compile and wrote this code myself. Once compiled, run the application in the browser, and browse to the address of FullPost controller. For those who confuse what is the URL lead to FullPost controller, here it is: http://localhost:<PORT>/FullController/Index/1 – We need to include Index/1 at the URL to provide the post ID of which we would like to view in single page.

For next tutorial, I'll be finishing up my tutorial on Simple Blog Application. So we could say that tutorial on how to create a simple blog application by using MVC 3 is now coming to an end. One more part to go, and then we will have a blog application code using MVC. Until my next tutorial, please leave a comment for any question. Discussion are mostly welcome.

Blogger Labels: Create,Simple,Blog,Application,life,task,tutorial,Negative,Zero,Post,Section,Part,admin,series,Cover,comments,Also,controller,reader,bottom,FullPost,Comment,data,article,LINQ,statement,System,Generic,NegativeZero,Mindscape,FullPostController,LightSpeedContext,context,Development,HttpGet,ActionResult,Index,UnitOfWork,CreateUnitOfWork,Find,equals,PostId,Author,Title,Email,View,ToList,code,definition,folder,Once,files,method,option,configuration,Select,Model,Class,Scaffold,template,IList,script,language,scroll,width,Category,Body,ViewBag,Written,item,margin,font,size,text,Leave,Above,razor,syntax,user,database,CommentController,HttpPost,Parse,SaveChanges,Layout,Content,Html,BeginForm,ValidationSummary,legend,LabelFor,EditorFor,ValidationMessageFor,Label,Website,TextAreaFor,Hidden,ActionLink,Back,List,piece,closure,error,FullController,PORT,Discussion,readers,articles,tutorials,Collections,Controllers,Categories,Scripts,codes,namespace,blogModel,postAuthor,postCategories,postTitle,postBody,postTag,comId,comAuthor,comEmail,comUrl,comBody,javascript,positionedPopup,winName,commentCount,href,blogger,newEntry,jquery,fieldset,editor,localhost


Thank you for your unbelievable support on Negative Zero - Permission to read and write blog for nearly 4 years. Don't forget to like Negative Zero on Facebook.
Blogirific.com Blog Directory





Post(s) you might like to read :

2 comments:

  1. Thanks for this article. I am a new blogger so this is very helpful. It’s hard to know how long it takes to make a successful blog, so “being patient” is among some of the best advice you can give. It’s easy to get discouraged when you don’t see movement, but this give me some encouragement.

    ReplyDelete
  2. It's stunning I had no clue about all this until the moment I stumbled upon this article of yours. Will you be so nice and provide an answer to my question. Do you happen to know how to defend your personal intellectual property from being stolen?

    ReplyDelete