Tuesday, 26 May 2015

ASP.NET with a REST API: Part 3

This is Part 3 of a sequence. Here are links for Part 1 and Part 2.
These instructions for ASP.NET MVC using Visual Studio 2013. We assume that Open Source Pyrrho server is running, the haikus database has been set up as in Part 1, and we are continuing the solution development from part 2.

Implementing Likes

We now implement likes using toggled icons.
1. . On any page that shows haikus, we show the user’s Likes.

So add this code to Views>Shared>HaikuPartial.cshtml. in the else part (not owner
if (Request.IsAuthenticated)
{
    Html.RenderPartial("LikeHaikuPartial", h);
}
2.  So, in Views>Shared, add a new Empty partial view called LikeHaikuPartial based on VERSE. (This is a first shot. In a couple of steps we will enable toggling of the Like.)
@using Haikus.Models
@model VERSE

@{
    var h = Model;
    var likes = false;
    var me = User.Identity.Name;
    foreach (var lk in Connect.conn.FindWith<LIKES>("VID="+h.ID+",UID="+me))
    {
          likes = true;
    }
    if (likes)
    {
        <img title="I like this" alt="I like this: " src="/Account/Picture/'_Liked'" />
    }
    else {
<img title="I don't like this" alt="I don't like this: " src="/Account/Picture/'_NotLiked'" />
    }

}
3.  Let’s add some Like/Dislike methods to the VERSE class in VERSE.cs.

It is easiest to have some real SQL here!
public static void Like(int id, string user)
{
   Connect.conn.Post(new LIKES{VID = id, UID = user });
}
public static void Dislike(int id, string user)
{
    Connect.conn.Act(
   "delete from Likes where vid=" + id + " and uid='" + user + "'");
}
public static VERSE Find(long id)
{
    return Connect.conn.FindOne<VERSE>(id);
}
4.  Let’s add similarly-named methods to the HomeController
public ActionResult Like(int id)
{
  Haikus.Models.VERSE.Like(id, User.Identity.Name);
  var v = (ViewBag.Author != null) ? "Author" : "Index";
  return View(v);
}
public ActionResult Dislike(int id)
{
  Haikus.Models.VERSE.Dislike(id, User.Identity.Name);
  var v = (ViewBag.Author != null) ? "Author" : "Index";
  return View(v);
}
5.  Finally change the LikeHaikuPartial view to use links.

 if (likes)
{
   <a href="@("/Home/Dislike/"+h.ID+"/")" >
   <img title="I like this" alt="I like this: " src="/Account/Picture/'_Liked'" />
    </a>
} else
{
    <a href="@("/Home/Like/"+h.ID+"/")" >
    <img title="I don't like this" alt="I don't like this: " src="/Account/Picture/'_NotLiked'" />
     </a>
}
Rebuild all. 
6. Check this works


For a logged in user clicking the heart icon should toggle its state.
Close the browser.

Adding a Details View

7. Let’s add a Details icon so we can find out the properties, comments etc of a haiku. Add the code shown to the HaikuPartial view before the @if(h.owner..
       <a href="@("/Home/Haiku/" + h.ID + "/")" >
         <img alt="Details" title="Details"
             src="@("/Account/Picture/'_Details'/")" />
       </a>
 8. Now add a method in the HomeController.

public ActionResult Haiku(long id)
{
     ViewBag.Haiku = id;
     return View("Haiku", VERSE.Find(id));
       // so we can call return Haiku(id) elsewhere
}
9.  And in Views>Home create a new View called Haiku. Use Empty, use VERSE as the model class, clear Create as a partial view and click Add. Give the code shown as the View
using Haikus.Models;
@model VERSE
@section right {
    <h3>Liked by:</h3>
    @{ foreach (var lk in Connect.conn.FindWith<LIKES>("VID="+Model.ID))
     {
        <a href="@("/Home/Likes/" + lk.UID + "/")">
    <img alt="@lk.UID" title="@("Haikus " + lk.UID + " likes")"
         src="@("/Account/Picture/" + lk.UID + "/")" /></a>
     }
    }
}
<h2>Haiku</h2>
@if (Model.owner(this))
{
    Contributed by you

    <a href="@("/Home/EditHaiku/" + Model.ID + "/")">
    <img alt="Pencil" title="Edit"
         src="@("/Account/Picture/'_Pencil'/")" /></a>
    <a href="@("/Home/Delete/" + Model.ID + "/")">
    <img alt="Delete" title="Delete"
         src="@("/Account/Picture/'_Delete'/")" /></a>
}
else
{
    Contributed by @Model.OWNR

    <img title="@Model.OWNR" alt="@Model.OWNR"
         src="@("/Account/Picture/" + Model.OWNR + "/")" />
}
<p>
    @foreach (var s in Model.CONT.Split('\r'))
    {
        @s<br />
    }
</p>
@if (Request.IsAuthenticated && !Model.owner(this))
{
    Html.RenderPartial("LikeHaikuPartial", Model);
}10.  We need a Likes method in the HomeController
public ActionResult Likes(string id)
{
   ViewBag.Author = id;
   return View(AUTHOR.Find(id));
}
11.  And a Home\Likes View (based on AUTHOR, not partial)
@{
    ViewBag.Title = "Home Page";
    string id = ViewBag.Author;
 }

<h2>Haikus that <img title="@id" alt="@id"  src="@("/Account/Picture/'" + id + "'/")" /> likes</h2>

    @foreach (var h in Haikus.Models.VERSE.Liked(id))
    {
        Html.RenderPartial("HaikuPartial", h);
    }
12.  We need Liked() in VERSE.cs. Add using System.Collections. Generic; at the top and a new method as shown.
public static VERSE[] Liked(string au)
{
    var vs = new List<VERSE>();
    foreach (var lk in Connect.conn.FindWith<LIKES>("AID=" + au))
       vs.Add(Find(lk.VID));
    return vs.ToArray();
}
Try it out and close the browser

Adding Comments

13. Let’s implement comments. Let’s add a method to COMMENT.cs. We need using System.Collections. Generic at the top.
public static COMMENT[] On(long id)
{
   var cs = new List<COMMENT>();
   foreach (var c in Connect.conn.FindWith<COMMENT>("VID=" + id))
   cs.Add(c);
   return cs.ToArray();
}
14.  Add a new Create partial view for COMMENT to Views/Home called NewCommentPartial
@model Haikus.Models.COMMENT
@section right {}
@using (Html.BeginForm("Comment/","Home"))
{
    @Html.AntiForgeryToken()
  
    <div class="form-horizontal">
        <h4>COMMENT</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="editor-field">
            @Html.TextAreaFor(m => m.CONT, 5, 80, null)
            @Html.ValidationMessageFor(m => m.CONT)
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>
 15. Add the code shown to Views/Home/Haiku
<div>
    @{ // Comments section
        var hc = COMMENT.On(Model.ID);
        if (hc.Count() > 0)
        {
        <h3>Comments</h3>
            foreach (var c in hc)
            {
        <p><img title="@c.AID" alt="@c.AID" src="@("/Account/Picture/' + c.AID + "/")" /> @c.CONT</p>
            }
        }
        if (Request.IsAuthenticated)
        {
            Html.RenderPartial("NewCommentPartial", new COMMENT { VID = Model.Id });
        }
}
</div>
16.  We need to be able to Add a Comment. Add a method to COMMENT.cs:
        public static void Add(COMMENT m)
        {
            Connect.conn.Post(m);
        }
17.  We need to handle the POST of a new comment. In HomeController:





[HttpPost]


public ActionResult Comment(COMMENT m)

{

     m.VID = long.Parse(Request["VID"]);

     m.CONT = Request["CONT"];

     m.AID = User.Identity.Name;

     Haikus.Models.COMMENT.Add(m);

     ModelState.Clear();

     return Haiku(m.VID);

}


18. Try it out.

 If you've just been reading along, the above view is reached by clicking the Details icon on the home page (or any other page that displays a list of haikus).
The sample can be continued with the implementation of tags and ratings. This is left as an exercise for the reader.

No comments:

Post a Comment