Sunday, September 25, 2016

Javascript: Function Hoisting

JavaScript makes two passes. During first pass,  js gathers all variable declarations (NOT assignments) and function definitions. In the second pass, js executes the code taking information learned in the first pass into consideration.

// hoisting supported for function definitions
// functions can be called before their definition appears in the file
a();

// hoisting NOT supported for function expressions
// variable b is declared but not assigned to yet
// Error: Uncaught TypeError: b is not a function
// b();

function a(){
    console.log('a');
}

var b = function (){
    console.log('b');
}

b();

Output:
a
b

Thursday, September 22, 2016

JavaScript: Variable Hoisting

JavaScript makes two passes. During first pass,  js gathers all variable declarations (NOT assignments) and function definitions. In the second pass, js executes the code taking information learned in the first pass into consideration.

Code example

(
function()
  {
  console.clear();
var i = 100;
console.log("S1.1 topmost: i = " + i);  
 
    function doIt1() {
      // NO other variable with name i is declared in this function
      //  therefore, i refers to i declared in the enclosing function
    console.log("S2.1 doIt1: i = " + i);
      // this corresponds to function scope
      //   no var named i declared in this function
      //   this has function scope
      console.log("S2.2 doIt1 (using this): i = " + this.i);
      // NOTE: var keyword is NOT used
      //    changes value of i declared in enclosing function
      i = 400;  // changes value of i defined in enclosing function
      console.log("S2.3 doIt1: i = " + i);
    }
 
    function doIt2() {
      // i is the var defined below (equals undefined so far)
      //   i is NOT the i declared in enclosing function
    console.log("S.3.1 doIt2: i = " + i);
      // this refers to i defined in this function
      console.log("S.3.2 doIt2 (using this): i = " + this.i);
      // i is declared in this function scope
      //   NOTE the use of var keyword
      //   hides i declared in the enclosing function
      // i is hoisted to the top of this function
      //   at the top of this function, i has value of undefined
      // now assign it a value
      do{
        // i is declared at function scope
        //   even though it is within the curly braces of while
        var i = 500;
      } while(false);
      // value is assigned to the local i
      console.log("S1.2 doIt2: i = " + i);
    }
 
    doIt1();
    doIt2();
 
    // i retains the value assigned in doIt1
    console.log("S1.3 topmost: i = " + i);
    console.log("this.xxx limits scope to the current function's curly braces!")
  }
)();

Output

S1.1 topmost: i = 100
S2.1 doIt1: i = 100
S2.2 doIt1 (using this): i = undefined
S2.3 doIt1: i = 400
S.3.1 doIt2: i = undefined
S.3.2 doIt2 (using this): i = undefined
S1.2 doIt2: i = 500
S1.3 topmost: i = 400
this.xxx limits scope to the current function's curly braces!

Wednesday, September 21, 2016

JavaScript by Code Examples


Declare and call an anonymous function in one go

(function(arg){
   console.log('called with arg: ' + arg);
})('param');

Output:
called with arg: param

Declare a named function and then call the function

function aFunc(arg){
   console.log('called with arg: ' + arg);
};

aFunc('param');

Output:
called with arg: param

Declare, assign and then call the function

var aFunc = function(arg){
   console.log('called with arg: ' + arg);
};

aFunc('param');

Output:
called with arg: param

Function Closure

aVar = "aVar - global scope";
console.log(aVar);

(function(){
var aVar = "aVar - function scope";
  console.log(aVar);
})();

console.log(aVar);

Output:
aVar - global scope
aVar - function scope
aVar - global scope

Nested Functions

function guid() {
        function s4() {
            return Math.floor((1 + Math.random()) * 0x10000)
              .toString(16)
              .substring(1);
        }
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
          s4() + '-' + s4() + s4() + s4();
    }

console.log(guid());

Output:
73a2bfd3-0a2f-bf5a-d029-aec390de6567

Creating function objects with state

var i = function (val){
// this. makes val a property of this object
this.val = val;

// helper function defined in i's scope
function consolePrint(msg){
console.log(msg);
}

this.Print = function() {consolePrint(this.val);}
}
var j = new i(4);  // create a new object based on i
var k = new i(5);  // create another new object based on i
j.Print();
k.Print();

Output:
4
5

Mimicking object-orientation (classes)

// just a normal js function assigned to a variable
var Circle = function (radius){
  this.radius = radius;  // create and assign data member
 };
// Through "prototype", methods declared after the function is initially declared
/    can be automatically
// added to every new instance of the object
Circle.prototype.area = 
  function() { return 22/7 * this.radius * this.radius; }; 
Circle.prototype.circumference = 
  function() { return 2 * 22/7 * this.radius; };

// use the function (class)
var circle1 = new Circle(4);
console.log("circle 1 radius = " + circle1.radius);
console.log("circle 1 area = " + circle1.area());
console.log("circle 1 circumference = " + circle1.circumference());

Output:
circle 1 radius = 4
circle 1 area = 50.285714285714285
circle 1 circumference = 25.142857142857142

Mimicking a Module with a function

// define module and create an instance of the module
var circle = new function(){

   this.area = function(radius){
    return 22/7 * radius * radius;
  };

  this.circumference = function(radius){
    return 2 * 22/7 * radius;
  };

}

// use module
var radius = 4;
console.log("radius = " + radius);
console.log("area = " + circle.area(radius));
console.log("circumference = " + circle.circumference(radius));

Output:
radius = 4
area = 50.285714285714285
circumference = 25.142857142857142

Mimicking a Module with a Json Object

// define module
var circle = {
 "area" : function(radius){
  return 22/7 * radius * radius;
  },
  "circumference" : function(radius){
  return 2 * 22/7 * radius;
  }
}

// use module
var radius  = 4;
console.log("radius = " + radius);
console.log("area = " + circle.area(radius));
console.log("circumference = " + circle.circumference(radius));

Output:
radius = 4
area = 50.285714285714285
circumference = 25.142857142857142

Safe console.log

var debug = true;

function log(msg){
    if (typeof console != 'undefined'
    && typeof console.log != 'undefined'
    && debug){
        console.log(msg);
    }
}

log('test');

Thursday, September 8, 2016

Parsing CSV string with LINQ

// As list of strings
List<string> ids = idsCsv
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.Where(x => !String.IsNullOrWhiteSpace(x))
.ToList();


// As list of integers
var ids = csvIds
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x =>
{
int id;
return int.TryParse(x, out id) ? id : -1;
})
.Where(x => x != -1)
.ToList();

Friday, June 17, 2016

C# run jobs (Task) on multiple threads, return upon completion of the first one

class Program
{
static void Main(string[] args)
{
Test();
Console.ReadKey();
}

static async void Test()
{
int result = await TaskTest();
Console.WriteLine(result);
}
static async Task<int> TaskTest()
{
Task<int> task1 = new Task<int>(() => { Thread.Sleep(1000); return 1; });
Task<int> task2 = new Task<int>(() => { Thread.Sleep(50); return 2; });
task1.Start();
task2.Start();
var multiTaskResult = await Task.WhenAny(task1, task2);
return multiTaskResult.Result;
}
}

Wednesday, June 8, 2016

ASP.Net MVC Multiple submit buttons on a Form

// Form markup
<input name="submit" type="submit" value="Download" class="btn btn-primary" />
<input name="submit" type="submit" value="Display" class="btn btn-primary" />

// Controller processor
public ActionResult SomeReport(SomeModel model,string submit)
{
if (submit == "Display")
{
return View(model);
}
else if (submit == "Download")
{
return DownloadReport(model);
}
}

ActionResult DownloadRevenueReport(RevenueReportListModel model)
{
return File(Encoding.UTF8.GetBytes(GetTextData(model)),
"application/text", "Report.csv");
}

Tuesday, June 7, 2016

ASP.Net MVC HTTP GET Controller Action Processing Pattern for Reports or Searches

Scenario


  • Select a month
  • Days of month are displayed on the same view


Controller

[HttpGet]
public ActionResult Index(ReportPageSelectionModel model, string msg)
{
String preSelectedMonth = null;
try
{
ViewBag.Msg = msg;

if (model.DisplayResults == false)
{
model.MonthList = ReportPageModelFactory.GetMonthList();
return View(model);
}
else
{
preSelectedMonth = model.SelectedMonth;
model.MonthList = ReportPageModelFactory.GetMonthList();
ReportPageResultModel resultModel =
ReportPageModelFactory.GetResultsModel(model.SelectedMonth);
ViewBag.Result = resultModel;
return View(model);
}
}
catch (Exception ex)
{
return RedirectToAction("Index", new { Msg = GetInnerMostException(ex).Message, SelectedMonth = preSelectedMonth });
}
}

Exception GetInnerMostException(Exception ex)
{
if (ex.InnerException == null)
return ex;
return GetInnerMostException(ex.InnerException);
}

View

@model ReportPageSelectionModel
@using ReportPage.Models

@{
    ViewBag.Title = "Report Page";
}

<div>
    <h3>Criteria Selection</h3>

    @using (Html.BeginForm("Index", "Home", FormMethod.Get))
    {
        <div class="form-horizontal">

            @Html.ValidationSummary(true, "", new { @class = "text-danger" })

            <div class="form-group">
                <div class="control-label col-md-3"><strong>@Html.LabelFor(model => model.SelectedMonth)</strong></div>
                <div class="col-md-9">
                    <div class="form-control-static">
                        @Html.DropDownListFor(model => model.SelectedMonth, Model.MonthList)
                    </div>
                </div>
            </div>

            <div class="form-group">
                <div class="col-md-offset-4 col-md-8">
                    <input type="hidden" name="DisplayResults" value="true" />
                    @Html.ActionLink("Reset", "Index", null, new { @class = "btn btn-default" })
                    <input type="submit" value="Go" class="btn btn-primary" />
                </div>
            </div>
        </div>
    }

    @if (@ViewBag.Msg != null)
    {
        <div class="alert alert-danger">
            <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
            <strong>@ViewBag.Msg</strong>
        </div>
    }

</div>

<hr />

@{
    var result = @ViewBag.Result as ReportPageResultModel;
}

@if (result != null)
{
    <div>
        <h3>Result</h3>
        @foreach(var day in result.Result)
        {
            <p>@day</p>
        }
    </div>
}

@section scripts
{
    <script>
        $(function () {
            $("#SelectedMonth").change(function () {
                $("form").submit();
            });
        });
    </script>
}

Models

public class ReportPageSelectionModel
{
[DisplayName("Month")]
[Required]
public string SelectedMonth { get; set; }
public List<SelectListItem> MonthList { get; set; }
public bool DisplayResults { get; set; }
}

public class ReportPageResultModel
{
public DateTime SelectedMonth { get; set; }
public List<string> Result { get; set; }
}


Model Factories

static public class ReportPageModelFactory
{
static public ReportPageResultModel GetResultsModel(string selectedMonthStr)
{
var model = new ReportPageResultModel();
model.SelectedMonth = DateTime.Parse(selectedMonthStr);
model.Result = new List<string>();
for (int i=1; i<= DateTime.DaysInMonth(model.SelectedMonth.Year, model.SelectedMonth.Month); i++)
{
DateTime day = new DateTime(model.SelectedMonth.Year, model.SelectedMonth.Month, i);
model.Result.Add(day.ToString("dddd MMMM d, yyyy"));
}
return model;
}

static public List<SelectListItem> GetMonthList()
{
var monthList = new List<SelectListItem>();
for (int i = 1; i <= 12; i++)
{
DateTime month = new DateTime(DateTime.UtcNow.Year, i, 1);
monthList.Add(
new SelectListItem()
{
Text = String.Format("{0}  {1}", month.Year, month.ToString("MMMM")),
Value = month.ToString()
});
}
return monthList;
}
}