5/20/17

AngularJS Recursive View Templates

In this article, we build an AngularJS collapsible menu with nested sub-menus from a hierarchical JSON model that can contain an undefined tree depth like the one shown below:


For the Angular2+ solution look at this article: Angular2 Recursive Views


JSON Model
Collapsible Menu





Our JSON model has a nested structure in which a node can have other nodes associated to the menu property. This model represents navigation groups and sub-groups for an app which can enable us to build a hierarchical menu. A common approach to render this model is to build a nested view that iterates through the arrays to display the information. Let’s look a simple implementation here:



<ul class="nav" style="width:200px" data-ng-controller="app.ctrl.dev as ctrl">
    <li data-ng-repeat="item in ctrl.menu">
        <a href="{{item.url}}" class="dropdown-toggle" data-toggle="collapse" title="{{item.title}}" data-target="#{{item.id}}">
            <i class="fa fa-fw fa-2x {{item.class}}"></i> <span class="nav-header-primary" data-ng-bind="item.title"></span>
            &nbsp;<span data-ng-if="item.menu" class="fa fa-caret-down fa-2x pull-right"></span>
        </a>
        <ul class="nav collapse" data-ng-if="item.menu" id="{{item.id}}">
            <li data-ng-repeat="subitem in item.menu" class="collapsed active">
                <a href="{{subitem.url}}" class="dropdown-toggle"  data-toggle="collapse" data-target="#{{subitem.id}}" title="{{subitem.title}}">
                    <i class="fa {{subitem.class}} fa-fw fa-2x"></i>
                    <span data-ng-bind="subitem.title"></span>
                    &nbsp;<span data-ng-if="subitem.menu" class="fa fa-caret-down fa-2x pull-right"></span>
                </a>
            </li>
        </ul>
    </li>
 </ul>


If we look at our implementation, we can see that our view have the nested HTML mark-up rendering the same model properties on the same HTML document structure. This may not be a problem if the levels on the JSON model are just two levels deep, but the moment we need to support more levels, the view becomes unmanageable as we need to duplicate more mark-up as shown on the example below:



<ul class="nav" style="width:200px" data-ng-controller="app.ctrl.dev as ctrl">
    <li data-ng-repeat="item in ctrl.menu">
        <a href="{{item.url}}" class="dropdown-toggle" data-toggle="collapse" title="{{item.title}}" data-target="#{{item.id}}">
            <i class="fa fa-fw fa-2x {{item.class}}"></i> <span class="nav-header-primary" data-ng-bind="item.title"></span>
            &nbsp;<span data-ng-if="item.menu" class="fa fa-caret-down fa-2x pull-right"></span>
        </a>
        <ul class="nav collapse" data-ng-if="item.menu" id="{{item.id}}">
            <li data-ng-repeat="subitem in item.menu" class="collapsed active">
                <a href="{{subitem.url}}" class="dropdown-toggle"  data-toggle="collapse" data-target="#{{subitem.id}}" title="{{subitem.title}}">
                    <i class="fa {{subitem.class}} fa-fw fa-2x"></i>
                    <span data-ng-bind="subitem.title"></span>
                    &nbsp;<span data-ng-if="subitem.menu" class="fa fa-caret-down fa-2x pull-right"></span>
                </a>
                <ul class="nav collapse" data-ng-if="subitem.menu" id="{{subitem.id}}">
                    <li data-ng-repeat="item3 in subitem.menu">
                        <a href="{{item3.url}}" title="{{item3.title}}">
                            <i class="fa {{item3.class}} fa-fw fa-2x"></i>
                            <span data-ng-bind="item3.title"></span>
                        </a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
   </ul>



In the example above, we can continue to nest more mark-up, but this eventually becomes unreadably, and it is still limited to the number of segments/levels that we implement on the view. If the model has a deeper level, our view does not account for that. We need to look for a dynamic way to handle these cases.

Recursive Views:

Luckily for us AngularJS let us include content into our app with the use of a directive.  The ngInclude directive can be used to recursively include the HTML mark-up as a template as we iterate thru the different levels. Let’s modify our mark-up to demonstrate this:

Entry Point:


<nav class="navbar" style="width:200px">
    <ul class="nav">
        <li data-ng-repeat="item in ctrl.menu" class="collapse" ng-init="level=1" ng-include="'recursiveView'">
        </li>              
    </ul>
</nav>



In our view, we first create the entry point to include a template into our content. We do this by adding the ng-include directive to load a template while we read the elements on the menu array using ngRepeat which is the step that allows us to create the item scope context that is used on the template.

The Recursive Template:


<script type="text/ng-template" id="recursiveView">
<a href="{{item.url}}" class="dropdown-toggle" data-toggle="collapse" title="{{item.title}}" data-target="#nav{{item.id}}">
    <i class="fa fa-fw fa-2x {{item.class}}"></i> <span class="nav-header-primary" ng-bind="item.title"></span>
    &nbsp;<span ng-if="item.menu" class="fa fa-caret-down fa-2x pull-right"></span>
</a>
<ul class="nav collapse" style="margin-left:{{level}}0px" data-ng-if="item.menu" id="nav{{item.id}}">
    <li ng-repeat="subitem in item.menu" data-ng-init="level=level+1;item=subitem" ng-include="'recursiveView'">
    </li>
</ul>      
</script> 



 Within the template itself, the item object properties are used to render the information. We also load the template again using the include directive while reading the item menu property. This enables us to iterate the nested model and inject the template as we navigate through the different levels recursively.

The solution supports n nested levels without duplicating the markup. A few key items to notice using this strategy are the following:

1 – Initialize the level scope variable: This enables to track the levels and add some padding by using an inline style markup.  We do not want to set a class name here since we want to support multiple levels dynamically.
2- Item as a scope variable: Notice how at the start we use ngRepeat directive and set the item scope variable. On the nested level, we use the subitem scope variable to iterate the item.menu array.  We need to use different scope variable names to prevent resetting the item scope context. However when we include the template again recursively, the subitem scope context is passed. Obviously, the view is expecting an item scope variable name instead of subitem.  To overcome this, we use the ngInit directive to set the item scope context to the subitem array. At this point, we no longer need the previous context, and we can continue to render the nested levels.

Once we have accounted for the scope variable problem, our recursive view should work properly. 
This can be seen in action on the following demo:

DEMO



As we can see, we now have support for multiple levels without having to duplicate all the HTML mark-up.


For the Angular2+ solution look at this article: Angular2 Recursive Views


Originally published by ozkary.com

4/8/17

SharePoint Gantt Chart Hidden with Bootstrap Master Page


SharePoint provides a Gantt chart web part that allows small teams to manage their projects. When using the default master pages, the web part renders with no problem.  In the cases when a custom Bootstrap master page is used, the right side panel of the Gantt grid does not display properly as shown on the image below:


By taking a look at the problem, we notice that Bootstrap uses the following CSS rule:


* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}


This causes the chart to not display properly because there is a CSS rule on the Gantt chart that sets a border on the date header. We can key on that element rule to override the Bootstrap style by adding the following to our custom CSS file that is loaded from the master page.


/*find inline style with the border rule at the end. */
div[style$="border: 1px solid rgb(171, 171, 171);"]
{
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box;
}


We want to override the rule just for that specific element and not affect other layout elements.  We have to use this selector because the server side controllers create dynamic ids on the elements, and we want to prevent this problem in any page where this web part is used.

The solution was to find inline styles set with a border to use a box-sizing content-box instead of border-box. This prevents the hidden behavior on the Gantt chart. After the change, our page should look like this:


Hope you can now see the chart.

Originally published by ozkary.com

3/25/17

Presentation Securing Web Apps with Azure AD

This is the presentation for the Securing Web Apps with Azure AD.  In this presentation, we talked about the following areas:

  • We take a Web application with an AngularJS SPA as client and NodeJS server with no security context, and we deploy it to Azure using a local GIT repository.
  • We configure the Azure Application with Azure AD and show the different behaviors with forcing the users to Login or allowing anonymous access.
  • We also discuss how to change a NodeJS server application and handle the security implementation in the server code.
  • We finally show how to make the implementation changes on the AngularJS SPA to allow the application to directly integrate with Azure AD.
Related Blog Entries:



For the code, visit:

Presentation



Originally published by ozkary.com

1/7/17

SQL Server BCP Import Skip and Map Columns Using Views

The BCP (bulk copy program) command line utility enables us to quickly import CSV files into a SQL Server database. The utility works very well when the import file matches the structure of the table, and the table does not have an identity column.
The moment the import file does not match the structure of the table with can run into different possible errors during the import.  This is mostly due to the fact that the fields may not mapped correctly to the columns on the table.

To facilitate the control of how the CSV fields should be mapped to the fields on the table, we can create a view that matches the CSV field order.  Let’s take a look at an example to illustrate the problem and a solution using SQL views.

The Table

This is a simple table that allows us to store blog entries.  We should note the identity and default datetime columns which would not exist in a CSV file as these are system generated values.


CREATE TABLE dbo.ozkary_blog
(
       id       int identity,
       title    nvarchar(200) null,
       url      nvarchar(100) null,
       tags     nvarchar(100) null,
       created  datetime null,
       imported datetime default(getdate()) not null
)



The CSV File

Our CSV file contains four fields which are fewer fields than columns on the table.


Created,title,url,tags


We should note the following possible issues when trying to import this CSV file with our previously define table.


  • The order of the columns on the table does not match the fields of the CSV file. The create date field is first on the file, but it is on position five on our table.

  • Our table has an identity field which sure will not match the date field on position one of our CSV file.

  • Our table also has an import date time field with a default date value.

Data Import Process

Let’s attempt to import the data directly into our table without any modifications. To import the file, we execute the following command:


bcp dataimport.dbo.ozkary_blog IN ".\\ozkary_blog.csv" -t, -c -F1 -S .\sqlexpress -T


When calling the BCP utility we use the following parameters:

Parameter  Option
Description
Database and table name
This is the database and table name
CSV file name and location
This is the file location and name
-t,
Comma is the field delimiter
-c
Use char as the storage type for all the fields
-F2
Start at row 2 column - skip field headers
-S
Server name
-T
Use a trusted connection with the current session

In our first attempt to import the data, we are using the table name. This does not work because of fields mapping to the wrong columns, and ,as expected, we get some data type errors (add –e bcp.log parameter to create a log file and see more detail on the errors)



Solution – Using a View to Map the Fields

To address this problem, we can create a view that only uses the fields that are available on the import file and match their corresponding order.


CREATE VIEW dbo.vw_import_ozkary_blog
AS
   SELECT created,title,url,tags
   FROM dbo.ozkary_blog



We should now modify the command and use the view name instead of the table name. This should provide better results.


bcp dataimport.dbo.vw_import_ozkary_blog IN ".\\ozkary_blog.csv" -t, -c -F2 -S .\sqlexpress -T





By looking at the output on the image above, 3 rows got imported. If we query our table we should see the records with our identity and imported date values.


As shown, the approach of importing a CSV file using a database view provides a consistent and simple way to map and skip table columns during a BCP import.


Hope it helps.

Originally published by ozkary.com