Popularni postovi

Monday, 30 June 2014

jQuery min v1.10.1 error reading jquery-1.10.1.min.map not found


You can use the map file for debugging purposes in the console of any modern browser and don't need to include the unminified version of jquery.
If you don't need it, simply remove sourceMappingURL in the jquery file, otherwise you can download the map file on jquery.com.

WebAPI Self referencing loop detected with type 'System.Data.Entity.DynamicProxie


Turn OFF Lazy Loading  in your EDMX because it serializes childs with parent table and create referencing loop. If you need (but ONLY if YOU REALY NEED) Lazy Loading then add this to WebApiConfig(but it will send huge amount of data...):

            var json = config.Formatters.JsonFormatter;
            json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

Sunday, 29 June 2014

$http get from controller

'use strict';
app.controller('ordersController', ['$http','$scope', 'ordersService', function ($http, $scope, ordersService) {

    $scope.orders = [];

    var serviceBase = 'http://localhost:26264/';


      $scope.orders = $http.get(serviceBase + 'api/orders')
    .success(function (data, status, headers, config) {
        $scope.orders = data;
        console.log(data);
        return data;
    }).error(function (data, status, headers, config) {
        alert("error");
        return status;
    });


}]);

Enable CORS

Enable CORS:

Install-Package Microsoft.AspNet.WebApi.Cors


Add this to WebApiConfig
var cors = new EnableCorsAttribute("localhost:32150", "*", "*"); // change here to site
config.EnableCors();

Tuesday, 3 June 2014

AngularJS and ASP.NET WebAPI Serveer-side sorting, searching and paging

An example of how to setup an html table with server-side paging, searching and sorting with AngularJS and ASP.NET WebAPI (and a little help from bootstrap).
Paging, searching and sorting server-side is a must if your working with large collections of data, if you've attempted to process thousands or millions of records in the browser then you know exactly how painful it can be, practically grinding the browser to a halt! Moving all this heavy lifting to the server will make your application much more responsive and drastically reduce the amount of bandwidth you're using.

The view contains three main elements, a search form, a table of users and a pagination control. All of the searching, sorting and paging parameters are encapsulated by a pagingInfo object.
The pagination directive is from the UI Bootstrap library which contains all the bootstrap components written in pure AngularJS (http://angular-ui.github.io/bootstrap/).
The css styling is from the bootstrap 3 framework.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<form class="form-inline" ng-submit="search()" role="form">
    <div class="form-group">
        <input type="text" class="form-control input-sm" ng-model="pagingInfo.search" placeholder="Search...">
        <button type="submit" class="btn btn-info btn-sm"><strong>Search</strong></button>
    </div>
</form>
<table class="table table-striped table-bordered table-hover table-condensed">
    <thead>
        <tr>
            <th><a href="" ng-click="sort('FirstName')">First Name</a></th>
            <th><a href="" ng-click="sort('LastName')">Last Name</a></th>
            <th><a href="" ng-click="sort('Username')">Username</a></th>
            <th><a href="" ng-click="sort('Email')">Email</a></th>
            <th><a href="" ng-click="sort('Role')">Role</a></th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="user in users">
            <td>{{user.FirstName}}</td>
            <td>{{user.LastName}}</td>
            <td>{{user.Username}}</td>
            <td>{{user.Email}}</td>
            <td>{{user.Role}}</td>
        </tr>
    </tbody>
</table>
<pagination page="pagingInfo.page"
            total-items="pagingInfo.totalItems"
            items-per-page="pagingInfo.itemsPerPage"
            on-select-page="selectPage(page)"
            max-size="10"
            rotate="false"
            boundary-links="true"></pagination>

The controller contains all of the functions for paging, sorting and searching the table of users, it sets the default values on the pagingInfo object and loads the users with an AngularJS factory called UserService.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
'use strict';
angular.module('Users')
.controller('Users.HomeController',
    ['$scope', 'UserService',
    function ($scope, UserService) {
        $scope.pagingInfo = {
            page: 1,
            itemsPerPage: 30,
            sortBy: 'FirstName',
            reverse: false,
            search: '',
            totalItems: 0
        };
         
        $scope.search = function () {
            $scope.pagingInfo.page = 1;
            loadUsers();
        };
        $scope.sort = function (sortBy) {
            if (sortBy === $scope.pagingInfo.sortBy) {
                $scope.pagingInfo.reverse = !$scope.pagingInfo.reverse;
            } else {
                $scope.pagingInfo.sortBy = sortBy;
                $scope.pagingInfo.reverse = false;
            }
            $scope.pagingInfo.page = 1;
            loadUsers();
        };
        $scope.selectPage = function (page) {
            $scope.pagingInfo.page = page;
            loadUsers();
        };
        function loadUsers() {
            $scope.users = null;
            UserService.GetUsers($scope.pagingInfo).success(function (data) {
                $scope.users = data.data;
                $scope.pagingInfo.totalItems = data.count;
            });
        }
        // initial table load
        loadUsers();
    }]);

The UserService makes an HTTP GET call to the ASP.NET Web API to get a list of users, passing the pagingInfo object as the parameters. The pagingInfo object gets converted into querystring parameters automatically by AngularJS.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
'use strict';
angular.module('Users')
.factory('UserService', ['$http',
    function ($http) {
        var service = {};
        service.GetUsers = function (pagingInfo) {
            return $http.get('/api/users', { params: pagingInfo });
        };
        return service;
    }]);

The Web API controller takes the parameters sent by the AngularJS service and returns a collection of users in JSON format.
I've hardcoded a dummy list of users for the example, but this would be replaced by a call to an ORM or some form of data repository in the real world, I recommend NHibernate.
The sorting functionality is done using the Dynamic LINQ Library, which there is surprisingly little about online but I've found extremely useful, you can install it via NuGet with the command Install-Package System.Linq.Dynamic.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class UsersController : ApiController
{
    public IHttpActionResult Get(
        int page = 1,
        int itemsPerPage = 30,
        string sortBy = "FirstName",
        bool reverse = false,
        string search = null)
    {
        // create list of 100 dumy users, replace
        // with call to repo in real app
        var users = Enumerable.Range(1, 100)
                .Select(x => new User
                {
                    Id = x,
                    FirstName = "FirstName" + x,
                    LastName = "LastName" + x,
                    Username = "Username" + x,
                    Email = "Email" + x,
                    Role = "Role" + x
                }).AsQueryable();
        // searching
        if (!string.IsNullOrWhiteSpace(search))
        {
            search = search.ToLower();
            users = users.Where(x =>
                x.FirstName.ToLower().Contains(search) ||
                x.LastName.ToLower().Contains(search) ||
                x.Username.ToLower().Contains(search) ||
                x.Email.ToLower().Contains(search) ||
                x.Role.ToLower().Contains(search));
        }
        // sorting (done with the System.Linq.Dynamic library available on NuGet)
        users = users.OrderBy(sortBy + (reverse ? " descending" : ""));
        // paging
        var usersPaged = users.Skip((page - 1) * itemsPerPage).Take(itemsPerPage);
        // json result
        var json = new
        {
            count = users.Count(),
            data = usersPaged.Select(x => new
            {
                Id = x.Id,
                FirstName = x.FirstName,
                LastName = x.LastName,
                Username = x.Username,
                Email = x.Email,
                Role = x.Role
            })
        };
        return Ok(json);
    }
}