Thursday, November 14, 2013

Week 4 Day

We're almost half way through the group project. It's going pretty well. We should have most of the functionality up today. That will give us time to add a good deal of polish and one or two new features before it finishes up.

If the functionality is up tomorrow, I want to spend next week working on an API/Widget that will allow a user to embed some of our functionality in their site.

Maybe we can get users added in next week also...maybe. I don't know what it involves but it would be an interesting challenge.


Tuesday, November 5, 2013

The Wheels Are Off



Week 3- Day 2: We've had two solid days of medium-ish sized projects. This week is starting out to be a bruiser. Loooong days.

On top of the projects I'm trying to squeeze in a mini-side project. A single page application written in Html, jQuery and AngularJs.

jQuery has been giving me fits. I'm trying to make it do something it wasn't really designed to do. That's why I brought Angular into the mix.

I hope to have it in beta by the end of the week...we'll see.

Friday, November 1, 2013

Pagination: Millions of Pages, Pages for Me (Part 1)

Here are the basics of setting up pagination in an ASP.net project using Razor. I'll post a video at the end of the series showing the whole process.

In Part 1, we're just going to set up the logic and a fixed pager
  1. You'll need to create a new project, using the MVC web template.
  2. Create a new class in your models folder called People. Give them 2 properties: Id and Name.
  3. Set up your database with entity framework. Seed it with 12 people. Here's my class & seed data.
Class
public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }

    }
Seeder
context.People.AddOrUpdate(
                p => p.Id,
                new Person { Id=1, Name="Alex" },
                new Person { Id=2, Name="Aaron" },
                new Person { Id=3, Name="Amish" },
                new Person { Id=4, Name="David" },
                new Person { Id=5, Name="Miguel" },
                new Person { Id=6, Name="Andrew" },
                new Person { Id=7, Name="Andy" },
                new Person { Id=8, Name="Josh" },
                new Person { Id=9, Name="Grey" },
                new Person { Id=10, Name="Yola" },
                new Person { Id=11, Name="Mark" },
                new Person { Id=12, Name="Max" },
                new Person { Id=13, Name="Ben" }
                );

Before we start building I think it's useful to look at how pagers work.

There are two key variables:
  1. How many results you want on a page: I'll call this variable PageSize. 
  2. What page the viewer is on. I'll call this CurrentPage. 
  3. There is a third variable called Skip that we'll get to in a second.
Lets look at what happens when a visitor uses our pager
 The visitor goes to our page for the first time. Page counting will start at 0.
Our Controller accesses the Database. Does any sorting. Sort first, or you're gonna have a bad time. THEN pulls the number of records we set PageSize. In this case lets assume we set it to three. The controller passes those records to the view, view displays those three records.

The visitor clicks over to page 2.

Same as before. Our Controller accesses the Database. Sorts.Skip requires some kind of sort even if it's just by Id. Does a Skip.  Then pulls the number of records we set in PageSize. To calculate the Skip you multiply the PageSize and CurrentPage.
First page you skip 0 (this is why you start counting pages at 0), Second page you skip 3, etc...

Go ahead and set up an MVC project, using the above classes and seeder, seed your database.

Onto Code...
Go into your home controller and create a new Action Result with a call to the database.

public ActionResult People()
        {
            ApplicationDbContext db = new ApplicationDbContext();             List<Person> people = db.People.ToList();

            return View(people);
        }
 
Create a view to match the new action result and put a loop creating a table in it.
<table class="table table-responsive table-striped">
    @foreach (var item in Model)
    {
        <tr><td>@item.Id</td><td>@item.Name</td></tr>
    }
</table>


You'll also want to add your @model statement to the top of your view if you haven't

@model IEnumerable<RaginPagin.Models.Person>

If you run this you get all of the results on a single page. We only want 3 results first. To get only 3 modify the People Action code as follows.

 public ActionResult People()
        {
            ApplicationDbContext db = new ApplicationDbContext();
           
            int PageSize = 3;

  
            List<Person> people = db.People.Take(PageSize).ToList();

            return View(people);
        }

We get three results on the first page but there's no way to move forward. We'll need something in the view to help us navigate. add the following under the table in your view.

<ul class="pagination">
    <li><a href="~/home/people/0">1</a></li>
    <li><a href="~/home/people/1">2</a></li>
    <li><a href="~/home/people/2">3</a></li>
    <li><a href="~/home/people/3">4</a></li>
    <li><a href="~/home/people/4">5</a></li>

</ul>

Note that the link text is one more than the CurrentPage
<li><a href="~/home/people/0">1</a></li>

If we run this, we'll still get the page, only three but the pages all return the same three results.
We need to go back to our HomeController and tell it what to do with the CurrentPage we're passing it at the end of the URL.

 public ActionResult People(int? id)
        {
            ApplicationDbContext db = new ApplicationDbContext();
          
            int PageSize = 3;
            skip = PageSize * id.Value;
           

            List<Person> people = db.People.OrderBy(p=>p.Id).Skip(skip).Take(PageSize).ToList();

            return View(people);
        }
Here is where we implement the Skip Linq call. Skip requires some sort or order on the data before it will run. I did this with another Linq call ordering the data by Id
The parameter of the current page is coming through as the id. It needs to be nullable to handle the default case of no parameter passed.

You then need to handle the possibility of Null for id. I handle it like this.

public ActionResult People(int? id)
        {
            ApplicationDbContext db = new ApplicationDbContext();
           
            int PageSize = 3;
            int skip = 0;
            if (id.HasValue) {
            skip = PageSize * id.Value;
            }

            List<Person> people = db.People.OrderBy(p=>p.Id).Skip(skip).Take(PageSize).ToList();

            return View(people);
        }
Here's the raw video an edited version is planned.