another technical blog...technically

Sunday, February 25, 2018

Just another Knockout paginator

I know I know, Knockout JS is something considered obsolete, but I loved it, so I decided right to write two posts about it to share some snippets I developed, maybe someone will find it useful. So the first post is about a simple paginator, the first snippet is the core of the paginator and you can put it in a common javascript (eg Custom.Utility.js), as you can see it behaviors as a plugin for knockout.
// Knockout utilities
if (typeof ko !== "undefined") {
 ko.bindingHandlers.fadeVisible = {
  init: function (element, valueAccessor) {
   $(element).fadeIn();
  },
  update: function (element, valueAccessor) {
   // Whenever the value subsequently changes, slowly fade the element in or out
   var value = valueAccessor();
   ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();
  }
 };
 ko.safeObservable = function (initialValue) {
  var result = ko.observable(initialValue);
  result.safe = ko.dependentObservable(function () {
   return result() || {};
  });
  return result;
 };
 ko.Paginator = function (observableValue) {
  var p = new Object();
  p.PageSize = ko.observable(10);
  p.PageIndex = ko.observable(0);
  p.PagesToShowSize = ko.observable(5);
  p.PagedItemsLength = ko.observable(0);
  p.IsVisible = ko.dependentObservable(function () {
   var length = observableValue().length;
   return (length > p.PageSize());
  });
  p.PagedList = ko.dependentObservable(function () {
   var size = p.PageSize();
   var start = p.PageIndex() * size;
   return observableValue().slice(start, start + size);
  });
  p.MaxPageIndex = ko.dependentObservable(function () {
   var l = observableValue().length;
   if (p.PagedItemsLength() !== l) {
    p.PagedItemsLength(l);
    p.PageIndex(0);
   }
   return Math.ceil(p.PagedItemsLength() / p.PageSize()) - 1;
  });
  p.PreviousPage = function () {
   var prev = p.PageIndex() - 1;
   if (p.PageIndex() > 0) {
    p.PageIndex(prev);
    p.MinPageRelativeIndex(prev);
   }
  };
  p.NextPage = function () {
   var next = p.PageIndex() + 1;

   if (p.PageIndex() < p.MaxPageIndex()) {
    p.PageIndex(next);
    p.MinPageRelativeIndex(next);
   }
  };
  p.MinPageRelativeIndex = ko.observable(0);
  p.MaxPageRelativeIndex = ko.dependentObservable(function () {
   var relativeMax = p.MinPageRelativeIndex() + p.PagesToShowSize();

   if (relativeMax > p.MaxPageIndex()) {
    var min = p.MaxPageIndex() - p.PagesToShowSize();
    p.MinPageRelativeIndex(min < 0 ? 0 : min);
    relativeMax = p.MaxPageIndex() + 1;
   }
   return relativeMax;
  });
  p.PagesToShow = ko.dependentObservable(function () {
   var pages = [];
   var minValue = p.MinPageRelativeIndex();
   var maxValue = p.MaxPageRelativeIndex();

   for (i = minValue; i < maxValue; i++) {
    pages.push({ PageNumber: (i + 1) });
   }
   return pages;
  });
  p.MoveToPage = function (index) {
   p.PageIndex(index);
  };
  return p;
 };
}
else {
 console.log("Knockout not imported... cannot decorate with new functions")
}
This second snippet is the declaration of the paginator in the HTML page, as you can see I refer to Custom.ViewModel as the namespace of the javascript. In the DIV class=”items” you are free to implement your preferred view, while in the DIV class=”paginator” you simply have to refer to the correct namespace.
...
Last but not least this is the initialization all the component in the Knockout controller.
// View model definition
controller.ViewModel = function ViewModel() {
 var vm = this;
 vm.Paginator = ko.Paginator(vm.Items);
 
 ...
};
Share:

Saturday, February 24, 2018

Blue Prism / DateTime / Code Stage / Locale issue

Since I’m at home with something like a broken shoulder (the right one), I got a lot of draft blog posts and a wonderful windows plugin named Dictate I think it’s the time to recover just a bit of work.
Today I want to talk about the behavior or daytime values when passed as an argument to code- stages. Even if Blue Prism discourages the use of code stages, I believe that this feature is one of the most interesting of them all and also helps to unleash the power of RPA. The problem with DateTime values in code stages is that BP represents them internally in UTC which could not be your locale (eg I work in Italy UTC+1)

Collection populated manually
Just passed as argument and returned

So BP suggests the following

If you do need to use a code stage then the following amendment at the end of the line will yield the behavior you expect:  The point is that you cannot always pre-process data, for example, if we take data from DB we cannot pre-process them but we have to deal with wrong data like you can see in the images below

Data from DB

Wrongdata after collection

The solution is just to post-process the data with this piece of code.
Dim dtItemValue As DateTime
Dim newDtItemValue As DateTime
Dim localZone As TimeZone
Dim span As TimeSpan

For Each row As DataRow In data.Rows
 For Each column As DataColumn In data.Columns
    dtItemValue = Nothing
    newDtItemValue = Nothing
    
    If column.DataType = System.Type.GetType("System.DateTime") Then
     dtItemValue = row(column)
     localZone = TimeZone.CurrentTimeZone
     span = localZone.GetUtcOffset(dtItemValue)
     spanString = span.ToString
     dtItemValue = dtItemValue.Add(span)
     newDtItemValue = dtItemVAlue.ToLocalTime
     row.SetField(Of DateTime)(column, newDtItemVAlue)
    End If
 Next
Next

dataOut = data
You have to take care that BP passes arguments by value and not by reference so could be necessary to use this code every time you passed the collection into the code-stages. A special credit to Raffaele Ecravino and Antonio Durante for this brief piece of code.

Me, myself and I

My Photo
I'm just another IT guy sharing his knowledge with all of you out there.
Wanna know more?