Thursday, July 31, 2014

AngularJS: manipulate rendered html data after AngularJS has rendered a template

I was working on the table row hover effect for a column span multiple rows ( like this Table Row Hovers with Rowspans, I actually borrowed the rowspan script with some twist )

The script works fine while I was working on ASP.NET MVC; however it started not working while I tried to reuse it for the app in AngularJS.

Why? AngularJS loaded in different time than ASP.NET MVC.... Here is what I figured it out after googling( sure! )

1. create a directive using angularJS $timeout service:
gicGiaApp.directive("ngTopload", ['$timeout', function ($timeout) {
    return {
        link: function ($scope, element, attrs) {
            $scope.$on('myDataloaded', function () {
                $timeout(function () { 

                 //This is the reused function I would like to call
                 //see the definition below 
                 RowSpanHover();  

                }, 0, false);
            })
        }
    };
}]);

2. add directive into the view template
....
<div class="ng-cloak" ng-cloak="" ng-topload="">
....
<table class="tgxxx" id="xxxTOP510"></table>
</div>


3. add this line into the controller to broadcast communicating with $on defined in the directive above:

.....
$scope.$broadcast('myDataloaded');
....



4.And here is the script function being reused both ASP.NET MVC and AngularJS:



function RowSpanHover() {

    $('#xxxResults .tgxxx tbody td').hover(function () {
        $element = $(this);
        $element.parent().prevAll('tr:has(td[colspan]):first').addClass("hover");
        if ($element.parent().has('td[rowspan]').length == 0)
            $element.parent().prevAll('tr:has(td[rowspan]):first').find('td[rowspan]').addClass("hover");
    }, function () {
        $element.parent().prevAll('tr:has(td[rowspan]):first').find('td[rowspan]').removeClass("hover");
    });

}

AngularJS: dynamically assign parameter for $scope

I need to have dynamic parameters assigned for $scope after getting data from server.

I think it is common since angularJS directives often need it for condition check etc.

so I defined a function then being called within success{} closure as below:
$scope.updateAllxxxSelect= function(obj) {

    $(obj).find("input:checked").each(function (i, ob) {
        var t = $(ob).val();
        //This is the line
        $scope[t] = true;
    });

    $(obj).find("input:not(:checked)").each(function (i, ob) {
        var t = $(ob).val();
        //This is the line
        $scope[t] = false;
    });
   
};

'Autodiscover service couldn't be located' error while calling exchange server

The code below had been working
           
    
           ExchangeService service = new ExchangeService();
            //Assign the URL. It is recommended to use AutoDiscoverUrl but we didn’t have it configured
            string exSvcUrl = "https://exchange_server_ip_or_name/ews/exchange.asmx";
            service.Url = new Uri(exSvcUrl);

            //Set service credentials. In this case a user account who has permissions to user mailboxes.
            string domain = "xxx";
            string credUser = "mxxx";
            string credPwd = "xxxxxx";
            service.Credentials = new System.Net.NetworkCredential(credUser, credPwd, domain);
            service.AutodiscoverUrl("xxx@xxxx.com");
            try
            {
                
                SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, DateTime.Now.AddHours(-12)), new SearchFilter.ContainsSubstring(EmailMessageSchema.Sender, "xxx"));

                ItemView view = new ItemView(20);

                FindItemsResults findResults = service.FindItems(
                new FolderId(WellKnownFolderName.Inbox, new Mailbox("xxxx@xxxx.com")),
                sf,
                new ItemView(200));
            }
            catch{...}
It worked for a while, then one day after office moved, it came out the error as below:
Autodiscover service couldn't be located

It took me a while to figure this out, googled to no avail. Here is version after fix:

                ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);


                //Assign the URL. It is recommended to use AutoDiscoverUrl but we didn’t have it configured
                service.Url = new Uri(exSvcUrl);

                //Set service credentials. In this case a user account who has permissions to user mailboxes.
                service.Credentials = new WebCredentials(credUser, CryptoUtility.Decrypt(credPwd, ParamForCrypto, SaltForCrypto), domain);

                if (debugMode) service.TraceEnabled = true;

                System.Net.WebProxy proxy = new System.Net.WebProxy("https://xxxx.com");
                proxy.UseDefaultCredentials = true;                

                //The search filter to get unread email

                SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, DateTime.Now.AddDays(daysToRetrieve*-1)), new SearchFilter.ContainsSubstring(EmailMessageSchema.Sender, mailbox_to_monitor));
               
                FindItemsResults findResults = service.FindItems(
                new FolderId(WellKnownFolderName.Inbox, new Mailbox(mailbox)),
                sf,
                new ItemView(200));

javascript: my version of endswith

C# has EndsWith however javascript does not provide that. Here is my version of it:
function  endsWith( targetStr, str ) {
    return targetStr.substr( -1 * str.length, str.length ) === str;
  }

or
if ( typeof String.prototype.endsWith != 'function' ) {
  String.prototype.endsWith = function( str ) {
    return this.substr( -1 * str.length, str.length ) === str;

  }
};

Tuesday, July 29, 2014

jquery: dynamically manipulate the href node

It is difficult to have dynamic look and feel using ASP.NET WebForm ( For the sake of the legacy code maintenance so I have to work with Webform from time to time instead of always ASP.NET MVC ), however using JQuery can help achieve that very handy:

$(function () {

        var spanId = '<%= liveTabLB.ClientID %>';
        var sortDirectionId = '<%= sortingDirection.ClientID %>';
        var current = $('#' + spanId).text();
        var sortDirection = $('#' + sortDirectionId).text();
        var sortTarget = $('#' + '<%= sortingTarget.ClientID %>').text();

        $('.tabs li').each(function (i, ob) {

            if ($(ob).text().indexOf(current) > -1) {
                if (!$(ob).hasClass('on')) $(ob).addClass('on');
            }
            else {
                if ($(ob).hasClass('on')) $(ob).removeClass('on');
            }

        });

        $('.lbTable .headerTR a').each(function (i, ob) {
            var tt = $(ob).text().replace(/ /g, '');
            var extraSpace = " ";
            var extraLine = "
"; var img = 'sort.png'; if (sortDirection === 'ASC' && tt === sortTarget) img = 'up.png'; else if (sortDirection === 'DESC' && tt === sortTarget) img = 'down.png'; var imgSpan = ""; var transformmed = $(ob).text().split(' ').join("
"); if (transformmed.indexOf(extraLine) > -1) $(ob).html(' ' + transformmed + imgSpan); else $(ob).html($(ob).text() + imgSpan + extraLine + extraSpace); }); });

JavaScript:To get subset of arrays based on the array object property using map and filter

It is easier to do this using LINQ in C#.
However there is no LINQ in Javascript....
To get subset of arrays based on the property

//company_To_Search is an array of object : { name:"xxx", selected: true}
var companySelected = company_To_Search.filter( function( obj ) {
      return obj.selected;
   });
OR

   // To get an array of 'name' property
   var companySelected = company_To_Search.map( function( obj ) {
     if(obj.selected) return obj.name;
   }).filter( function( obj ) {
     return typeof obj !== 'undefined';
   });

 //another example to get a list of Id of the object array
  filters.CompoundFreq = initCriteria.CompoundFreqs.map( function( obj ) {
     return obj.Id;
   }).filter( function( obj ) {
     return typeof obj !== 'undefined';
   });
using underscore reduce:
// To get an array of 'name' property companySelected = _.reduce(company_To_Search, function(memo, company) { if (company.selected) { memo.push(company.name); } return memo; }, []);
using underscore pluck:
// To get an array of 'name' property _.pluck(_.filter(companySelected, function(company) { return company.selected; }), "name");

Thursday, July 24, 2014

query to datatable using LINQ C# ; DataTable Clone and copy



       


private DataTable DataForXXX(DataTable dt,string queryParam)
{
            //Get All Data?  just return
            if (queryParam.Equals(allCities)) return dt;

            // Clones the structure of the DataTable,
            // including all DataTable schemas and constraints.
            DataTable dtCopy = dt.Clone();


           // query to DataTable
            var results = from DataRow myRow in dt.Rows
                          where branch.Equals(
myRow["Branch"] as string,StringComparison.CurrentCultureIgnoreCase)
                          select myRow;


            foreach (var row in results)
            {
               // Use ImportRow otherwise error:
               // "This Row already belongs to another table"
                dtCopy.ImportRow(row);
            }

            return dtCopy;

}

Tuesday, July 22, 2014

AngularJS: Toggle sorting columns between ascending and descending


Here is what I had done:



1.  On server side, I  created a model which has a State property for the table header:


    public class GICResultsModel
    {
       
        public string TermTarget { get; set; }

       
        public int Count { get; set; }

       
        public int Current { get; set; }

       
        public int PageSize { get; set; }

       
        public List<dcm_xxx_searchResult> SearchResults { get; set; }

       
        public List<HeadData> Header { get; set; }

       
        public List<string> HeaderIds { get; set; }


    }

    public struct HeadData
    {
        public string Id { get; set; }
        public string Disc { get; set; }

        /// <summary>
        /// This is the State to hold the toggling state
        /// </summary>
        public bool State { get { return false; }  }
    }




2.  inside the view:

        <tr class="headerTR" ng-show="xxxResultModel.Header.length > 0">          
              <th ng-repeat="m in gicResultModel.Header">  
  <span class="spanLink" ng-click="searchCall(m.Id,-1)" >{{m.Disc}}</span></th>
      </th>
   
        </tr>




3.  inside the Controller code:

xxxApp.controller('xxxsearchController', function($scope,$http,$routeParams) {

            // In case we use route params
        if( typeof $routeParams.id === 'undefined' || $routeParams.id === null)  searchPage = 1;
else if( $routeParams.id === "0" || $routeParams.id === "-1") {
              searchPage = 1 ; $('#sortingDirection').val($routeParams.id === "-1"? "1" : "0");
          }
else searchPage = !isNaN(parseInt( $routeParams.id ))
                                        ? parseInt( $routeParams.id )
                                        : 1;

if( !(typeof $routeParams.t === 'undefined' || $routeParams.t === null || $routeParams.t === 'null'))
                 searchSortingTarget = $routeParams.t;
         
            inProcess = true;

   
$('#xxxSearchCriteria').show();
$('#xxxTopFilters').hide();

$scope.searchCall = function(sortingTarget,page){
var isSorting = false;
var header = null;//a temp param to hold the state

if(page===-1){

                        ///////////////////////////////////
                        //HERE Toggle the state
this.m.State = !this.m.State;
                        ///////////////////////////////////

$('#sortingDirection').val(this.m.State?1:0);
$('#sortingTarget').val(this.m.Id);
sortingTarget = this.m.Id;
page = 1;
isSorting = !isSorting;

                        //assign the updated Header with sorting state to 'header'
if($scope.xxxResultModel!==null) header = $scope.xxxResultModel.Header;
}

var params = new FiltersModel(sortingTarget,page);

       $http.post('/xxx/Browser/Services/xxxHandler.ashx', JSON.stringify(params))
                      .success(function (data, status, headers, config) {
                                               $scope.xxxResultModel = data;

                                                ////////////////////////////////////////
                                                //The Magic happens here:
                                                //We keep the header data
                                                //by replacing using the updated header state
if( header!==null ) $scope.xxxResultModel.Header = header;

$scope.current = data.Current==-1?1:data.Current;

inProcess = false;
                                            })
                    .error(function (data, status) {
                        $scope.errors.push(status);
inProcess = false;
                    });
 };

 $scope.searchCall(searchSortingTarget,searchPage);

                 //This is for custom paging use
 $scope.getPageTotal = function(){
             
var high = Math.ceil(
                                                                              $scope.xxxResultModel.Count
                                                                              /$scope.xxxResultModel.PageSize
                                                                              );
var low = 1;
var arr = [];

while(low <= high){
arr.push(low++);
}
return arr;

};
});

Convert Linq2SQL Result To DataTable

I met a situation I need to convert Linq2SQL result to DataTable so I can take advantage of the GridView sorting ( binding to datatable instead of binding to list )etc.


Here is the sample code to do it with Reflection:



            DataTable dataTable = new DataTable();

            foreach (var prop in typeof(xxx_get_xxxxboardResult).GetProperties())
            {
                Type type = prop.PropertyType;
             
                 ////////////////////////////////////////////////////////////////////////////////
                //Nullable Type would throw error if without this below
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    type = Nullable.GetUnderlyingType(prop.PropertyType);


                dataTable.Columns.Add(prop.Name, type);
            }
         
            ISingleResult<xxx_get_xxxxResult> linq2SQLResult = null;
            using (System.Data.Linq.DataContext context = new System.Data.Linq.DataContext())
            {
                linq2SQLResult = context.xxx_get_xxxxboard(city);

                foreach (var advisor in linq2SQLResult.ToList())
                {
                    DataRow dataraw = dataTable.NewRow();

                    foreach (var prop in typeof(xxx_get_xxxxboardResult).GetProperties())
                    {
                        dataraw[prop.Name] = typeof(xxx_get_xxxxboardResult).GetProperty(prop.Name).GetValue(advisor,null);
                    }
                 
                    dataTable.Rows.Add(dataraw);
                }

            }

Exchange Server: EWS Managed API complex Filters

How to Add complex search filters to the search filter collection


I do not see Microsoft provided detailed enough documents for this,  I figured it out so i would like to share  here:




// mailbox_to_monitor is the param for the 
var mailbox_to_monitor = string.IsNullOrEmpty(ConfigurationManager.AppSettings["mailboxToMonitor"]) ? targetFilePath : ConfigurationManager.AppSettings["mailboxToMonitor"];

            
//The 1st filter tries to filter based on the mail body 
SearchFilter sf1 = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, DateTime.Now.AddDays(daysToRetrieve * -1)), new SearchFilter.ContainsSubstring(ItemSchema.Body, mailbox_to_monitor));

//The 2st filter tries to filter based on the mail sender
                SearchFilter sf2 = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, DateTime.Now.AddDays(daysToRetrieve * -1)), new SearchFilter.ContainsSubstring(EmailMessageSchema.Sender, mailbox_to_monitor));

////////////////////////////////////// // logical OR with filter 1 and filter 2
//This is the line to do the trick
                SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, sf1, sf2);


FindItemsResults<Item> findResults = service.FindItems(
                new FolderId(WellKnownFolderName.Inbox, new Mailbox(mailbox)),
                sf,
                new ItemView(200));


                var mailResults = findResults.OrderBy(t => t.DateTimeSent);


//Loop through the items and do whatever is required.
                string data = string.Empty;
                var emailMsgs = new List<string>();
                var hrefList = new List<string>();
                foreach (var i in mailResults)
                {

                    i.Load();
                    var msgBody = i.Body;
                    var msgText = msgBody.Text;

                    if (msgText.Contains("Value_You_Try_To_Look_At")) emailMsgs.Add(msgText.Trim());

                    data = String.Format("{0}{1} On: {2} – Subject: {3}", data, Environment.NewLine, i.DateTimeReceived.ToString(), i.Subject);


                }