The Family Page–Part 8, Wish list and Angular.js second try

Since last time where I started using Angular.js with Angular resources and services, I have been reading a bit and I decided on a little bit different approach. I want to use WebApi on the backend, and Angular factories and controllers. With my current (limited) knowledge of angular, the extra layer of abstraction using a resource makes things a little more difficult to understand without really giving any benefits. This might change later in the process, but right now this is the way I am going.

What I am showing here is strongly inspired by Dan Wahlin’s post on the subject. Using an angularjs factory to interact with a restful service.

In this post I will

  • Add WebApi to an existing MVC project
  • Use controller and factory in Angular.js to get the data from the WebApi controller.
  • Update the view view and data structure a little bit in order to group wishes by user. (instead of just having a flat list).

Adding WebApi

In order to use WebApi we need to set up WebApi routing, which is similar to, but separate from ASP.Net MVC routing. I add the WebApiConfic.cs file to Auth_Start, which is automatically added if you start out with a WebApi project:

using System.Web.Http;

namespace TheFamilyPage.App_Start
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

 

I the call this from Global.asax in GlobalConfiguration line (also completely standard, if you start out with a WebApi project)

using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

using TheFamilyPage.App_Start;

namespace TheFamilyPage
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

 

I then add WebApi controller for the wishes. In order to get the same functionality as I had before, I have implemented the “Get” Wishes part:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Mvc;

using TheFamilyPage.Models;
using TheFamilyPage.ViewModel;

namespace TheFamilyPage.Controllers
{
  public class WishApiController : ApiController
  {
    private ApplicationDbContext db = new ApplicationDbContext();

    // GET api/
    public async Task Get()
    {
      var tmpWishes = await db.Wishes.ToListAsync();

      var wishesByUsername = tmpWishes.GroupBy(x => x.User.Name);
      var wishes = new List<UserWishesViewModel>();
      foreach (var w in wishesByUsername)
      {
        var userWishes = new UserWishesViewModel();
        userWishes.Wishes = w.Select(x => new WishMViewodel(x)).ToList();
        userWishes.Name = w.Key;
        wishes.Add(userWishes);
      }

      if (wishes == null) throw new HttpResponseException(HttpStatusCode.NotFound);
      return Request.CreateResponse<IEnumerable<UserWishesViewModel>>(HttpStatusCode.OK, wishes); 
      
    }

    // GET api//5
    public string Get(int id)
    {
      return "value";
    }

    // POST api/
    public void Post([FromBody]string value)
    {
    }

    // PUT api//5
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api//5
    public void Delete(int id)
    {
    }
  }

  
}

I have also added a new ViewModel for the wishes in order to group the wishes by user, instead of having on flat list:

using System.Collections.Generic;

using TheFamilyPage.Models;

namespace TheFamilyPage.ViewModel
{
  class UserWishesViewModel
  {
    public string Name { get; set; }
    public List<WishMViewodel> Wishes { get; set; }
  }
  
  public class WishMViewodel
  {
    public WishMViewodel(Wish wish)
    {
      Id = wish.Id;
      Note = wish.Note;
      Shop = wish.Shop;
      TheWish = wish.TheWish;
      Url = wish.Url;
      UserId = wish.User.Id;
    }

    public string UserId { get; set; }
    public string Url { get; set; }
    public string TheWish { get; set; }
    public string Shop { get; set; }
    public string Note { get; set; }
    public int Id { get; set; }
  }
}

 

Setting up Angular factory and controller.

Now it is time to setup up the angular factory and controller. As mentioned before I find this much easier to work with at the moment, instead of using Services and Resources. Feel free to disagree.

The code is pretty straight forward – first the factory, which right now only supports getting the wishes:

var ngWishApp = angular.module("ngWishApp", []);

ngWishApp.factory('dataFactory', [
  '$http', function($http) {
    var urlBase = '/api/WishApi';
    var dataFactory = {};

    dataFactory.getWishes = function() {
      return $http.get(urlBase);
    }

    return dataFactory;
  }
]);

 

and the controller:

ngWishApp
  .controller('wishController', [
    '$scope', 'dataFactory',
    function($scope, dataFactory) {

      $scope.status;
      $scope.wishes;

      getWishes();

      function getWishes() {
        dataFactory.getWishes()
          .success(function(w) {
            $scope.wishes = w;
          })
          .error(function(error) {
            $scope.status = 'Unable to load wish data: ' + error.message;
          });
      }
    }
  ]);

 

You will notice that the controller calls getWishes() in order to initialize $scope.wishes.

Settings up the View

To finish our re-implementation heres is the updated view – note that I didn’t have to change the view to make it work, but I wanted to group the wishes by user, so I updated the view a little bit:

@model IEnumerable
"~/js/wish.js"></script>

@{
    ViewBag.Title = "Index";
}

<h2>Wishes</h2>

<div ng-app="ngWishApp">
  <div ng-controller="wishController">
    <div ng-repeat="items in wishes">
      <h2>{{items.Name}}</h2>
      <ul>
        <li ng-repeat="item in items.Wishes">
          {{item.TheWish}}, {{item.Url}}, {{item.Shop}}, {{item.Note}} 
        </li>
      </ul>
    </div>
    <div>{{status}}</div>
  </div>
</div>
<p>

 

A test run shows this:

image

So everything is working nicely.

This time I simply reimplemented what we did last time but I added WebApi and used controller and factory in angular to get the job done.

Next time I will add full CRUD functionality.

Advertisements

About Lund

Owner of iCodeIT, a software consulting company. I am primarily working the .NET development and architecture.
This entry was posted in ASP.NET MVC, javascript, WebAPI and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s