X

Subscribe To Our Mailing List

P.S I will never spam you...100% GUARANTEED!

Friday, October 23, 2015

Child action only in MVC


Introduction

The public methods in the controller class can be called as action. So the actions can be invoked through the URL. But the child actions cannot be directly accessed through the URL instead it will be called from the view.


How to Use

Suppose we have to display the same information across couple of pages /views then we can create a partial view and this partial view can be used in those views.

Child Actions cannot be accessed through the URL. It should be called from the parent view. From the parent view we can use -

@Html.Action("ChildActionMethod", "ControllerName")

Or we can call the child action methods like this -

@{ Html.RenderAction("ChildActionMethod", "ControllerName"); }

And my child action methods should be decorated with the attribute - "ChildActionOnly" - which signifies the action can be called only as a child.

Below is my sample child action method -

[ChildActionOnly]
public ActionResult ChildActionMethod()
{
    return PartialView();
}

So as mentioned above, this child action can be called from -

@Html.Action -> Returns the action result as HTML String.  

@Html.RenderAction -> Renders the action result directly into the view.  

And as you can observe my child action is returning the partial view. Its not mandatory for child action to return the partial view always but its a good practice to return the partial view over view.

If you are accessing the child action method through URL you will get a error like -



Hope it helps. Please comment your thoughts below.





Friday, October 9, 2015

AngularJS Grid Example


Introduction

In this article i will try to show the sample grid in AngularJS and adding the button in each row to get the selected row details. I will use the same sample Web API service created in my previous article.


Practical Approach

Below is the screenshot of the sample project created -



Now lets move on to each file in the project -

<!doctype html>
<html>

<head>
<title> Grid Example </title>

</head>

<body ng-app="myApp">
   <div class="page-content">
   <div class="row">
    <div class="col-md-2">
    <div class="sidebar content-box" style="display: block;">
     <ul class="nav">
      <!-- Main menu -->
       <li>
         <a href="#/GridExample" <i class="glyphicon glyphicon-home"></i> Grid Example</a>
       </li>
      </ul>
    </div>
     </div>
     
   <div class="col-md-10">
      <div class="content-box-header panel-heading">
     <div class="panel-title">Sample Grid Example</div>
      </div>

    <div class="row">
     <div class="col-md-12 panel-info">
      <div class="content-box-large box-with-header">
       <div ng-view></div>
      </div>

     </div>
    </div>

   </div>
  </div>
 </div>

<!-- Libaries for Bootstrap for controls -->
<!--Starts Here-->
<link href="scripts/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="scripts/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet" />
<script type="text/javascript" src="scripts/bootstrap/js/bootstrap.min.js"></script>
<!--Ends Here-->

<script type="text/javascript" src="scripts/angular.min.js"></script>
<script type="text/javascript" src="scripts/angular-route.js"></script>

<link href="css/styles.css" rel="stylesheet" />
<link href="content/ui-grid/ui-grid-unstable.css" rel="stylesheet" />
<link href="content/css/custom.css" rel="stylesheet" />

<script type="text/javascript" src="scripts/ui-grid-unstable.js"></script>

<script src="app.js"></script>
<script src="config.js"></script>

<script src="services/sampleService.js"></script>
<script src="controllers/sampleController.js"></script>

</body>
</html>

Above "index.html" has the references for controllers, services and stylesheet files. Library - "ui-grid-unstable.js" is used for loading the grid and it has functions required by the grid and stylesheet file also highlighted above.

If you checked my article it has all these files created already but in this example i will modify the controller part but service will be untouched.

So controller code for loading the grid -

myApp.controller('sampleCtrl', ['$scope', '$http', 'sampleService', function ($scope, $http, sampleService) {
 var products = sampleService.getProducts();

 products.then(function (response) {
  $scope.gridOptions = {
   data: response.data
  };
 });

 $scope.getProdName = function (row) {
  alert(row.entity.ProductName);
 };

 $scope.gridOptions = {
  enableFiltering: false,
  enablePaging: true,
  onRegisterApi: function (gridApi) {
   $scope.gridApi = gridApi;
  },
  columnDefs: [
    { name: 'Product Id', field: 'ProductId', width: 150 },
    { name: 'Product Name', field: 'ProductName' },
    {
     name: 'Details',
     cellTemplate: '<button class="btn btn-info btn-xs" 
                          ng-click="grid.appScope.getProdName(row)">View Product Name</button>',
                 enableFiltering: false,
                 enableSorting: false
       }
   ]
};

}]);


As shown above button control is added in "cellTemplate" section and on click of the button, product name value of the respective row will be popped up using function - "getProdName()".

For grid to work we should add the dependency while registering a module -

var myApp = angular.module('myApp', ['ngRoute', 'ui.grid']);

Below is the screenshot of the working example -



Hope this helps.




Thursday, October 8, 2015

Spinner Control For AngularJS


Introduction

In this article lets add a spinner control to show the loading of data in our AngularJS application.
I will use the same sample Web API service created in my previous article.


Practical Approach

As i said i am going to use the same Web API service and below is the project structure of AngularJS application -



Nothing fancy. It has the basic structure of AngularJS application. Now lets go through each file here in the solution -

I have a root file - "Index.html" which is my parent page and


<!doctype html>
<html>

<head>
 <title> Spinner Example </title>

</head>

<body ng-app="myApp">
 <div class="page-content">
  <div class="row">
   <div class="col-md-2">
    <div class="sidebar content-box" style="display: block;">
     <ul class="nav">
      <!-- Main menu -->
      <li><a href="#/SpinnerExample"<i class="glyphicon glyphicon-home"></i> Spinner Example</a></li>
     </ul>
    </div>
   </div>
   <div class="col-md-10">
    <div class="content-box-header panel-heading">
     <div class="panel-title">Sample Spinner Example</div>
    </div>

    <div class="row">
     <div class="col-md-12 panel-info">
      <div class="content-box-large box-with-header">
       <div ng-view></div>
      </div>

     </div>
    </div>

   </div>
  </div>
 </div>

 <span us-spinner="{radius:30, width:8, length: 16}"></span>

 <!-- Libaries for Bootstrap for controls -->
 <!--Starts Here-->
 <link href="scripts/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
 <link href="scripts/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet" />
 <script type="text/javascript" src="scripts/bootstrap/js/bootstrap.min.js"></script>
 <!--Ends Here-->

 <script type="text/javascript" src="scripts/angular.min.js"></script>
 <script type="text/javascript" src="scripts/angular-route.js"></script>

 <link href="css/styles.css" rel="stylesheet" />
        <!-- Libaries for Spinner--> 
        <!--Starts Here-->
        <script type="text/javascript" src="scripts/spinner/spin.min.js"></script>
 <script type="text/javascript" src="scripts/spinner/angular-spinner.min.js"></script>
 <script type="text/javascript" src="scripts/spinner/angular-loading-spinner.js"></script>
        <!--Ends Here-->
        <script src="app.js"></script>
 <script src="config.js"></script>

 <script src="services/sampleService.js"></script>
 <script src="controllers/sampleController.js"></script>

</body>
</html>

This file has all relevant file paths like - controllers, scripts and services, which are required for this demo and observe the line required for spinner control is highlighted along with spinner scripts.

For demonstration purpose i have created a service - "sampleService.js", which will call the Web API
service to get the data.

myApp.service('sampleService', function ($http) {
 this.getProducts = function () {
  return $http.get('http://localhost:53308/api/Product/');
 }
});

And controller which uses the above service -

myApp.controller('sampleCtrl', ['$scope', '$http', 'sampleService', function ($scope, $http, sampleService) {
 var products = sampleService.getProducts();

 products.then(function (response) {
  //once the process data
 });

}]);

As can be seen in the above code, when the data process is completed spinner is hidden and if there is a pending http request then the spinner is shown as per the below line of code in "index.html" -

<span us-spinner="{radius:30, width:8, length: 16}"></span>

Below is the directive is used for spinner -

(function () {
 angular.module('ngLoadingSpinner', ['angularSpinner'])
    .directive('usSpinner', ['$http', '$rootScope', function ($http, $rootScope) {
     return {
      link: function (scope, elm, attrs) {
       debugger;
       $rootScope.spinnerActive = false;
       scope.isLoading = function () {
        return $http.pendingRequests.length > 0;
       };

       scope.$watch(scope.isLoading, function (loading) {
        $rootScope.spinnerActive = loading;
        if (loading) {
         elm.removeClass('ng-hide');
        } else {
         elm.addClass('ng-hide');
        }
       });
      }
     };

    }]);
}).call(this);

Below is the screenshot of the spinner in the page -



and Plunker working demo - http://plnkr.co/edit/2bkqH67BURHqPHvXFpQT?p=preview

Hope this helps.




Tuesday, October 6, 2015

Form validation in Angularjs Part - 1

Introduction

This article focuses on adding the validation on form elements. This article will cover the basic validations in AngularJS and in coming posts i will try to cover the custom validation and dynamic validations.

Approach

Lets discuss some basic form validations in AngularJS -

Below is the Angular application structure -




Here one controller - "validationController.js" is added just one HTML page - "index.html" is added for adding the form controls.


Below is the content of "index.html" -

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>AngularJS Validations</title>

<link href="css/bootstrap.min.css" rel="stylesheet" />
</head>
<body ng-controller="validationCtrl">

<script src="scripts/angular.min.js"></script>

<script src="app.js"></script>
<script src="controllers/validationController.js"></script>

<form name="validationForm" novalidate class="form-horizontal" ng-submit="validationViewModel.submit()">

<!-- Text Validation-->
<div class="form-group">
 <label class="col-lg-2 control-label">Name</label>
     <div class="col-sm-2">
         <input type="text" class="form-control" ng-model="validationViewModel.Name" placeholder="Enter Name" name="Name" 
              required 
              ng-maxlength="10" 
              ng-minlength="5" /> 
     </div>

     <div class="help-block" style="color:red" ng-messages="Name.$error" 
                  ng-show="validationForm.Name.$dirty && validationForm.Name.$invalid">
           <span ng-show="validationForm.Name.$error.required">Enter Name.</span>
           <span ng-show="validationForm.Name.$error.maxlength">Maximum limit reached.</span>
    <span ng-show="validationForm.Name.$error.minlength">Enter Minimum length.</span>
     </div>
</div>


<!-- Email Validation-->
<div class="form-group">
  <label class="col-lg-2 control-label">Email</label>
      <div class="col-sm-2">
           <input type="email" class="form-control" ng-model="validationViewModel.Email" placeholder="Enter Email" name="Email" 
                 required />
      </div>
   
     <div class="help-block" style="color:red" ng-messages="Email.$error" 
                ng-show="validationForm.Email.$dirty && validationForm.Email.$invalid">
          <span ng-show="validationForm.Email.$error.required">Enter Email.</span>
          <span ng-show="validationForm.Email.$error.email">Enter Valid Email.</span>
     </div>
</div>

<!-- RadioButton Validation-->
<div class="form-group">
  <label class="col-lg-2 control-label">Gender</label>
      <div class="col-sm-2">
           <input type="radio" class="form-control" ng-model="validationViewModel.Gender" placeholder="Select Gender" value="male" 
               name="Gender" 
               required />
           <input type="radio" class="form-control" ng-model="validationViewModel.Gender" placeholder="Select Gender" value="female" 
               name="Gender" 
               required />
       </div>
    
     <div class="help-block" style="color:red" ng-messages="Gender.$error" 
               ng-show="validationForm.Gender.$dirty && validationForm.Gender.$invalid">
           <span ng-show="validationForm.Gender.$error.required">Select Gender.</span>
     </div>
</div>

<div class="form-group">
  <div class="col-lg-offset-2 col-sm-8">
       <button type="submit" class="btn btn-primary" ng-click="submitted=true">Save</button>
   </div>
</div>

</form>

</body>
</html>
);

As shown above there are 3 types of validations - "Text, "Email" and "Radio button" validations.

Validations will  be done whenever the controls are changed ($dirty) and the value is invalid. ($invalid).

So suppose if you want the validations to be fired irrespective of "$dirty" flag or on the click "Save" button then we can add some tweak to the existing HTML like below -

<div class="form-group">
  <div class="col-lg-offset-2 col-sm-8">
       <button type="submit" class="btn btn-primary" ng-click="submitted=true">Save</button>
   </div>
</div>


To the existing button control add the ng-click event to make the "submitted" to true. And existing validations can be modified like below -

ng-show="submitted || (validationForm.Email.$dirty && validationForm.Email.$invalid)"> 

So do the above changes in all the places wherever it is required. This line code to check whether directly "Save" button is clicked or else follow the same validations rules.

After adding this line of code this is how our page shows -



Plunkr Demo - http://plnkr.co/edit/GHZ4sflo7IV7ynLf1wNS?p=preview

Hope this helps.




Monday, October 5, 2015

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource. (Reason: CORS header 'Access-Control-Allow-Origin' missing).


Problem Statement

When working with AngularJS and Web API this issue can be seen. Lets create a sample Web API and AngularJS project to reproduce this issue and lets find the solution to this as well.

Demo

First create a sample Web API project and add - "ProductController.cs" file -

public class ProductController : ApiController
{
 private List _products;

 public ProductController()
 {
  _products = new List() { new Product() { ProductId = 1, CategoryId=100, ProductName ="Prod1"},
   new Product() { ProductId = 2, CategoryId=100, ProductName ="Prod2"}};
 }

 // GET api/product
 public List Get()
 {
  return _products;
 }

 // GET api/product/5
 public Product Get(int id)
 {
  return _products.First(a => a.CategoryId == id);
 }

 // POST api/product
 public void Post([FromBody]Product prod)
 {
  _products.Add(prod);
 }

}

Now lets create a sample html page for AngularJS application. Here lets main concentrate on the service part, which is doing a AJAX call to the Web API service -


myApp.service('sampleService', function ($http) {
 this.getProducts = function () {
  return $http.get('http://localhost:53308/api/Product/'); // Different domain call.
 }
});


As we can see in the above code. Web API running in the different domain than the client application. Below is the screenshot of error -



Solution

As a part of solution add the "<customHeaders>" tag to web config like below -

<httpProtocol>
  <customHeaders>
  <add name="Access-Control-Allow-Origin" value="*" />
  <add name="Access-Control-Allow-Headers" value="Content-Type" />
  <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
  </customHeaders>
  </httpProtocol>


Hope this post is useful. Please put your thoughts in the comment section below.