Support us .Net Basics C# SQL ASP.NET ADO.NET MVC Slides C# Programs Subscribe Buy DVD

angularjs ui-router nested views

Suggested Videos
Part 48 - AngularJS ui router custom data
Part 49 - AngularJS ui router html5mode
Part 50 - ui router active state css



In this video we will discuss nested states and views.



One of the benefits of ui-router over ngRoute is that it provides support for nested states and views. Nested states have parent child relationship. This means properties of the parent state are available to the child state. There are several methods for nesting states. The following are the 2 common methods.

1. Using 'dot notation'. In the example below "students" is a child of "studentParent" state. Notice in the child state name "studentParent.students" we are using . (DOT)

.state("studentParent", {
    // parent state config properties
})
.state("studentParent.students", {
    // child state config properties
})

2. Using the parent property with the parent name as string. In the example below, we are using parent property in the child state to specify who the parent is for this state.

.state("studentParent", {
    // parent state config properties
})
.state("students", {
    parent: "studentParent",
    // child state config properties
})

Let us understand nested states and views with an example. Here is what we want to do. On the students and studentDetails pages, we want to display student totals i.e the total number of male students, female students and grand total at the top of the pages in addition to the data these pages are already displaying.

Students page should be as shown below

angularjs ui-router nested states

StudentDetails page should be as shown below

angularjs ui-router nested views

Step 1 : Create a studentTotals class. We will use this class as a container for student totals.

namespace Demo
{
    public class studentTotals
    {
        public int total { get; set; }
        public int males { get; set; }
        public int females { get; set; }
    }
}

Step 2 : Create a web service method in StudentService.asmx, that returns student totals.

[WebMethod]
public void GetStudentTotals()
{
    studentTotals totals = new studentTotals();

    string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
    using (SqlConnection con = new SqlConnection(cs))
    {
        SqlCommand cmd = new SqlCommand("SELECT COALESCE(Gender, 'GrandTotal') AS Gender, COUNT(*) AS Total FROM tblStudents GROUP BY ROLLUP(Gender)", con);
        con.Open();
        SqlDataReader rdr = cmd.ExecuteReader();
        while (rdr.Read())
        {
            switch (rdr["Gender"].ToString())
            {
                case "Male":
                    totals.males = Convert.ToInt32(rdr["Total"]);
                    break;
                case "Female":
                    totals.females = Convert.ToInt32(rdr["Total"]);
                    break;
                default:
                    totals.total = Convert.ToInt32(rdr["Total"]);
                    break;
            }
        }
    }

    JavaScriptSerializer js = new JavaScriptSerializer();
    Context.Response.Write(js.Serialize(totals));
}

Step 3 : In script.js create "studentParent" state which will be the parent for "students" and "studentDetails" state. The parent state has it's own controller and template which we will create in just a bit. The resolve property retrieves student totals. This data will be available for the child states as well. We also have set abstract property to true. This makes the parent state an abstract state. Abstract states cannot be activated. They are implicitly activated when a child state is activated. The URL of the abstract state will be prepended to the URL of all the child states. The parent resolve property resolved dependencies and the custom data exposed via data property will be available for use by child states.

.state("studentParent", {
    url: "/students",
    controller: "studentParentController",
    controllerAs: "stdParentCtrl",
    templateUrl: "Templates/studentParent.html",
    resolve: {
        studentTotals: function ($http) {
            return $http.get("StudentService.asmx/GetStudentTotals")
                    .then(function (response) {
                        return response.data;
                    })
        }
    },
    abstract: true

})

Step 4 : In script.js, modify students and studentDetails to be child states. As the URL from the parent abstract state is prepended to the child state URL, the redundant part of the URL (/students) has been removed from both the child states (students & studentDetails).

.state("studentParent.students", {
    url:"/",
    templateUrl: "Templates/students.html",
    controller: "studentsController",
    controllerAs: "studentsCtrl",
    resolve: {
        studentslist: function ($http) {
            return $http.get("StudentService.asmx/GetAllStudents")
                    .then(function (response) {
                        return response.data;
                    })
        }
    }
})
.state("studentParent.studentDetails", {
    url:"/:id",
    templateUrl: "Templates/studentDetails.html",
    controller: "studentDetailsController",
    controllerAs: "studentDetailsCtrl"
})

Step 5 : In script.js create studentParentController function. Notice that resolved dependency is injected into the controller function.

.controller("studentParentController", function (studentTotals) {
    this.males = studentTotals.males;
    this.females = studentTotals.females;
    this.total = studentTotals.total;
})

Step 6 : Create student parent template. Add a new html file. Name it studentParent.html. On this template student totals are displayed using three <h3> elements. We also have a <ui-view> element into which the child states (i.e. students & studentDetails) will inject their content.

<h3>Total Male Students : {{stdParentCtrl.males}}</h3>
<h3>Total Female Students : {{stdParentCtrl.females}}</h3>
<h3>Grand Total : {{stdParentCtrl.total}}</h3>

<ui-view></ui-view>

Step 7 : In index.html modify students link. Notice the student state name is prepended with parent state name.

<a ui-sref="studentParent.students" ui-sref-active="activeState">Students</a>

Step 8 : In students.html, modify ui-sref directive value. Notice the studentDetails state name is prepended with parent state name.

<ul>
    <li ng-repeat="student in studentsCtrl.students">
        <a ui-sref="studentParent.studentDetails({id: student.id})">
            {{student.name}}
        </a>
    </li>
</ul>

Step 9 : In studentDetails.html modify "Back to Students list" link. Notice the student state name is prepended with parent state name.

<h4><a ui-sref="studentParent.students">Back to Students list</a></h4>

Step 10 : The parent state resolved dependencies are available to child states. To prove this, we want to display the total number of students on the students page against the List of Students text.

angularjs ui router nested resolve

To achieve this

a) Inject studentTotals resolved dependency into the studentsController function and assign it to the view model

.controller("studentsController", function (studentslist, $state, $location, studentTotals) {
    var vm = this;

    vm.studentSearch = function () {
        $state.go("studentsSearch", { name: vm.name });
    }

    vm.reloadData = function () {
        $state.reload();
    }

    vm.students = studentslist;
    vm.studentTotals = studentTotals;

})

b) In students.html, display the student total.

<h1>List of Students({{studentsCtrl.studentTotals.total}})</h1>

AngularJS tutorial for beginners

No comments:

Post a Comment

If you like this website, please share with your friends on facebook and Google+ and recommend us on google using the g+1 button on the top right hand corner.