Quantcast
Channel: Infragistics Community
Viewing all 2223 articles
Browse latest View live

High Performance Angular Grid with Web Sockets

$
0
0

You may have come across the requirement to push data in real time to an Angular Grid. To push data to the browser, you need a technology called WebSocket. You can implement that using NodeJS or ASP.NET SignalR. For the purpose of this article, we will use Web Sockets with NodeJS. 

In the first half of this article, we will create an API which will use Web Sockets to push data to the client, and, in second half of the article, we will create an Angular application to consume that. In the Angular application, we will use Ignite UI for Angular Grid.  However, you can also use a simple HTML table to consume data in real time from web socket. In this article, we will learn to consume data in real time from NodeJS Web Socket in a HTML table as well as Ignite UI Angular Data Grid. We will witness difference in performance in these two approaches.

You can learn more about Ignite UI for Angular: here

NodeJS API

Let us start with creating NodeJS API. Create a blank folder and add a file called package.json. In package.json, add dependencies of

  • Core-js
  • Express
  • io

 More or less your package.json file should look like below:

{
  "name""demo1",
  "version""1.0.0",
  "description""nodejs web socket demo",
  "main""server.js",
  "dependencies": {
    "core-js""^2.4.1",
    "express""^4.16.2",
    "socket.io""^2.0.4"  },
  "scripts": {
    "test""echo \"Error: no test specified\" && exit 1"  },
  "author""Dhananjay Kumar",
  "license""ISC"
}

You can pull data from any type of database such as relational data base, No SQL database, etc. However, for purpose of this post, I am going to keep it simple and have hardcoded data in the data.js file. This file will export a JSON array, which we will push using web socket and timer.

Add a file in folder called data.js and add the following code in it.

data.js

module.exports = {
    data: TradeBlotterCDS()
};
 
function TradeBlotterCDS() {
    return [
        {
            "TradeId""1",
            "TradeDate""11/02/2016",
            "BuySell""Sell",
            "Notional""50000000",
            "Coupon""500",
            "Currency""EUR",
            "ReferenceEntity""Linde Aktiengesellschaft",
            "Ticker""LINDE",
            "ShortName""Linde AG",
            "Counterparty""MUFJ",
            "MaturityDate""20/03/2023",
            "EffectiveDate""12/02/2016",
            "Tenor""7",
            "RedEntityCode""DI537C",
            "EntityCusip""D50348",
            "EntityType""Corp",
            "Jurisdiction""Germany",
            "Sector""Basic Materials",
            "Trader""Yael Rich",
            "Status""Pending"        }
        // ... other rows of data 
    ]
}

You can find data with 1200 rows here.

 From data.js file, we are returning TradeBlotter data. Now in your project folder, you should have two files: package.json and data.js

At this point in time, run the command, npm install, to install all dependencies mentioned in package.json file. After running command, you will have the node_modules folder in your project folder.  Also, add server.js file in the project.  After all these steps, your project structure should have following files and folders.

  • js
  • js
  • Node_modules folder

 In server.js, we will start with first importing required modules,

const express = require('express'),
    app = express(),
    server = require('http').createServer(app);
io = require('socket.io')(server);
let timerId = null,
    sockets = new Set();
var tradedata = require('./data');

Once required modules are imported, add route-using express as below:

app.use(express.static(__dirname + '/dist'));

On connecting the socket, we are performing following tasks:

  1. Fetching data
  2. Starting timer(We will talk about this function later in the post)
  3. On disconnect event deleting the socket
io.on('connection', socket => {
 
    console.log(`Socket ${socket.id} added`);
    localdata = tradedata.data;
    sockets.add(socket);
    if (!timerId) {
        startTimer();
    }
    socket.on('clientdata', data => {
        console.log(data);
    });
    socket.on('disconnect', () => {
        console.log(`Deleting socket: ${socket.id}`);
        sockets.delete(socket);
        console.log(`Remaining sockets: ${sockets.size}`);
    });
 
});

Next we have to implement, startTimer() function. In this function, we are using JavaScript setInterval() function and emitting data in each 10 millisecond time frame.

function startTimer() {
    timerId = setInterval(() => {
        if (!sockets.size) {
            clearInterval(timerId);
            timerId = null;
            console.log(`Timer stopped`);
        }
        updateData();
        for (const s of sockets) {
            s.emit('data', { data: localdata });
        }
 
    }, 10);
}

We are calling a function updateData() which will update data. In this function, we are looping through local data and updating two properties, Coupon and Notional, with random number between ranges.

function updateData() {
    localdata.forEach(
        (a) => {
            a.Coupon = getRandomInt(10, 500);
            a.Notional = getRandomInt(1000000, 7000000);
        });
}

We have implemented getRandomInit function as shown below:

function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min)) + min;
}

By putting everything together, sever.js should have following code

Server.js

const express = require('express'),
    app = express(),
    server = require('http').createServer(app);
io = require('socket.io')(server);
let timerId = null,
    sockets = new Set();
var tradedata = require('./data');
 
var localdata;
 
app.use(express.static(__dirname + '/dist'));
 
io.on('connection', socket => {
 
    console.log(`Socket ${socket.id} added`);
    localdata = tradedata.data;
    sockets.add(socket);
    if (!timerId) {
        startTimer();
    }
    socket.on('clientdata', data => {
        console.log(data);
    });
    socket.on('disconnect', () => {
        console.log(`Deleting socket: ${socket.id}`);
        sockets.delete(socket);
        console.log(`Remaining sockets: ${sockets.size}`);
    });
 
});
 
function startTimer() {
    timerId = setInterval(() => {
        if (!sockets.size) {
            clearInterval(timerId);
            timerId = null;
            console.log(`Timer stopped`);
        }
        updateData();
        for (const s of sockets) {
            s.emit('data', { data: localdata });
        }
 
    }, 10);
}
 
function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min)) + min;
}
 
function updateData() {
    localdata.forEach(
        (a) => {
            a.Coupon = getRandomInt(10, 500);
            a.Notional = getRandomInt(1000000, 7000000);
        });
}
 
server.listen(8080);
console.log('Visit http://localhost:8080 in your browser');

We have created Web Sockets in NodeJS, which is returning data chunk each 10 milliseconds.

Creating Angular Application

In this step, let us create Angular application. We are going to use Angular CLI to create an application and then add Ignite UI for Angular Grid. Follow the below article to create an Angular application and add Ignite UI for Angular Grid in the application.

https://www.infragistics.com/community/blogs/b/infragistics/posts/four-simple-steps-to-working-with-ignite-ui-for-angular-grid-and-rest-service

 If you are following above article, you need  changes in step three in which we are creating Angular service to consume API.

Let us start with installing socket.io-client in Angular project. To do that run npm install,

npm i socket.io-client

 We will write an Angular service to create the connection with NodeJS Web Socket. In app.service.ts, let us start with importing.

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { map, catchError } from 'rxjs/operators';
import * as socketIo from 'socket.io-client';
import { Socket } from './interfaces';

We have imported required modules. Later we will see how socket type is defined inside interface.ts file.  Next, let us create make connection to Web Socket and fetch next data from the response. Before returning the next data chunk from the web socket, we are converting that to an Observable.

getQuotes(): Observable < any > {
    this.socket = socketIo('http://localhost:8080');
    this.socket.on('data', (res) => {
        this.observer.next(res.data);
    });
    return this.createObservable();
}
 
createObservable(): Observable < any > {
    return new Observable<any>(observer => {
        this.observer = observer;
    });
}

The above two functions, will make connection to web socket, fetch data chunk, and convert that to observable. Putting everything together, app.service.ts will look like the below:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { map, catchError } from 'rxjs/operators';
import * as socketIo from 'socket.io-client';
import { Socket } from './interfaces';
 
@Injectable()
export class AppService {
 
    socket: Socket;
    observer: Observer<any>;
 
    getQuotes(): Observable<any> {
        this.socket = socketIo('http://localhost:8080');
        this.socket.on('data', (res) => {
            this.observer.next(res.data);
        });
        return this.createObservable();
    }
 
    createObservable(): Observable<any> {
        return new Observable<any>(observer => {
            this.observer = observer;
        });
    }
 
    private handleError(error) {
        console.error('server error:', error);
        if (error.error instanceof Error) {
            let errMessage = error.error.message;
            return Observable.throw(errMessage);
        }
        return Observable.throw(error || 'Socket.io server error');
    }
 
}

In the service, we are using a type called Socket. We created this type in file interfaces.ts as below:

export interface Socket {
    on(event: string, callback: (data: any) => void);
    emit(event: string, data: any);
}

Now Angular service is ready which will make connection to NodeJS Web socket and fetch data from the API as observable.

This is normal Angular service and can be consumed in a component in the usual way. Start with importin that in the module and then injecting that in component constructor as shown below:

constructor(private dataService: AppService) { }

we can call service method to fetch data in OnInit life cycle,

ngOnInit() {
    this.sub = this.dataService.getQuotes()
        .subscribe(quote => {
            this.stockQuote = quote;
            console.log(this.stockQuote);
        });
}

Putting everything together, component class will look like the below.   

import { Component, OnInit, OnDestroy } from '@angular/core';
import { AppService } from './app.service';
import { Subscription } from 'rxjs/Subscription';
 
@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
 
    stockQuote: number;
    sub: Subscription;
    columns: number;
    rows: number;
    selectedTicker: string;
 
    constructor(private dataService: AppService) { }
 
    ngOnInit() {
        this.sub = this.dataService.getQuotes()
            .subscribe(quote => {
                this.stockQuote = quote;
                console.log(this.stockQuote);
            });
    }
    ngOnDestroy() {
        this.sub.unsubscribe();
    }
}

One important thing you may want to notice is that we are unsubscribing the observable returned in OnDestroy life cycle hook of the component.  On the template, simply render data in table as below:

<table>    <tr *ngFor="let f of stockQuote">        <td>{{f.TradeId}}</td>        <td>{{f.TradeDate}}</td>        <td>{{f.BuySell}}</td>        <td>{{f.Notional}}</td>        <td>{{f.Coupon}}</td>        <td>{{f.Currency}}</td>        <td>{{f.ReferenceEntity}}</td>        <td>{{f.Ticker}}</td>        <td>{{f.ShortName}}</td>    </tr></table>

 

Since we are rendering data in real time in a normal HTML table, you may experience flickering and some performance issue. Let us replace HTML table with Ignite UI for Angular grid.

Learn more about Ignite UI for Angular Grid here: https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html  and you can learn to work with Ignite UI for Grid and REST Service in four simple steps here

You can add Ignite UI Grid in Angular application as shown below. We have set data source of the igxGrid using data property binding and then manually adding columns to the grid.

<igx-grid [width]="'1172px'" #grid1 id="grid1" [rowHeight]="30" [data]="stockQuote"          [height]="'600px'" [autoGenerate]="false">    <igx-column [pinned]="true" [sortable]="true" width="50px" field="TradeId" header="Trade Id" [dataType]="'number'"> </igx-column>    <igx-column [sortable]="true" width="120px" field="TradeDate" header="Trade Date" dataType="string"></igx-column>    <igx-column width="70px" field="BuySell" header="Buy Sell" dataType="string"></igx-column>    <igx-column [sortable]="true" [dataType]="'number'" width="110px" field="Notional" header="Notional">    </igx-column>    <igx-column width="120px" [sortable]="true" field="Coupon" header="Coupon" dataType="number"></igx-column>    <igx-column [sortable]="true" width="100px" field="Price" header="Price" dataType="number">    </igx-column>    <igx-column width="100px" field="Currency" header="Currency" dataType="string"></igx-column>    <igx-column width="350px" field="ReferenceEntity" header="Reference Entity" dataType="string"></igx-column>    <igx-column [sortable]="true" [pinned]="true" width="130px" field="Ticker" header="Ticker" dataType="string"></igx-column>    <igx-column width="350px" field="ShortName" header="Short Name" dataType="string"></igx-column></igx-grid>

Few points you should focus on in the grid we created:

  1. By setting height property, you can enable virtualization on the Ignite UI for Angular grid.
  2. By setting sortable property, you can enable sorting on the particular column.
  3. By setting pinned property, you can pin a column to the left of the grid.
  4. By setting data property, you can set data source of the grid.
  5. You can add columns manually by using <igx-column/>.
  6. Field and header of <igx-column/> is used to set field property and header of the column.


Now when you run the application, you will find grid is updating in real time with data and also not flickering. You will find grid is updating every 10 milliseconds.

In this way, you can push data in real time using NodeJS Web Socket API in Angular application. I hope you find this article useful. If you like this post, please share it. Also, if you have not checked out Infragistics Ignite UI for Angular Components, be sure to do so! They have 50+ Material-based Angular components to help you code web apps faster.


8 Ways to Improve Your Data Visualizations

$
0
0

When working with data sets, it’s important to make sure that your data is being properly and efficiently presented to your audience while following best practices for data visualizations. There are many different features and tricks you can use on your visualizations to make sure it’s understandable, succinct, and informative. Here are some quick formatting choices and additions that will improve overall readability and meaning behind your graphs and charts.

1) Conditional Formatting

Conditional formatting gives you quick indicators for the skew of your data based on the given bounds that you have previously assigned to it. For example, if having a quota over 65% is proficient, between 65% and 55% is fair, and below 55% is poor, then you can quickly see with conditional formatting who is meeting the expected quota and who is not.

2) Add Trendlines

You can show data trend or moving averages in your charts by adding a trendline. Trendlines are a very simple, yet powerful tool to help you determine trends in data sets and define thresholds for taking action. There are a number of trendlines out there that you can use on your visualizations depending on your data.

 

 

3) Filter by Rule

Filtering by rule allows you to either add a quick filter option to your axes or your data. Seeing sales by day may be an important aspect to a lot of managers and executives in companies, but, when you pull in every single day like you see below, it is hard to make sense of the data. By filtering this down to the last 30 or even 7 days you can more clearly see the days of low and high sales.

You can also do this with your data points as well. For example you may be in a company with a long list of sales representatives. Trying to create a visualization that shows you how each on is performing may not be effective. Instead looking at the top 10 or 20 sales representative, filtering by rule will allow you to gauge who is always performing well (or vice versa for bottom 10 or 20).

4) Add a Hierarchy

Adding hierarchy to your visualization will allow you to view data from a high level and drill down into specifics as you begin to ask questions. By adding a hierarchy to the data below, you are able to show both the total sales of each sales rep and then break that down even further by product. This eliminates the need to create extra visualizations and extra work!

You can also use this feature in a chart just as a bar chart that will allow you to drill down into a sales reps by product sales by simply clicking on their corresponding bar.

 

5) Sort Your Data

When your data isn’t based on date-oriented viewing, sorting the data either in descending or ascending order will visually display what story you are trying to tell. The example below shows your how you can quickly tell that “Complete” is the bestselling product and “Enterprise” is the worst performing in sales.

 

6) Format Your Data

Formatting your data can be a quick, simple way to make the numbers more visually appealing and easier to read to an end user. For either gauges or charts such as bar charts and column charts, you can adjust your data formatting to show a certain number of decimals, comma separators, displays as numbers, currency, percentage, or large number formatting.

 

7) Include a Comparison

You can both improve and add more insights to your visualizations by including comparisons to your charts. You can display your data based on date, like year over year, or you can use a comparison chart to compare two data points such as budget vs actual.

  

8) Chart Title

Keep your chart title simple and to the point since your data and visualization should tell the story. Primarily, your title should directly relate and support the chart underneath of it. 

 

Following a few or all of these best practices for data visualizations will begin to help you better present your important data. In turn, remember that half the battle is having a tool at your fingertips that enables you to make these edits and choices. Be sure to take a look at ReportPlus, a way to bring true self-service BI to any business.

How to Update to the Latest Version of Ignite UI CLI

$
0
0

In this blog post, we will learn systematically about how Ignite UI CLI can be updated to the latest version.

Learn more about Ignite UI CLI here

To know the current version installed on your machine run the command,

ig –v

This should give you current version as shown below:

The current version of Ignite UI CLI on my system is 1.3.0.  Now, I’ll want to update my version to create a new Angular app.

For this, we’ll update Ignite UI CLI to the latest version using the command,

npm i -g igniteui-cli

 

After successfully updating Ignite UI CLI, run the first command again to check the version installed.

ig- v

 

This should give you updated current version as shown below:

Now, on your system, you should have updated version 1.3.1 of Ignite UI CLI.  We can go aheadand create a new Angular project with latest version of Ignite UI CLI.

Let’s create a new Angular project using

 

ig new demo3  --framework=angular

 

In package.json, you can check that new project has been created using latest version of Ignite UI for Angular,

Then add an Ignite UI for Angular Grid to the application using following command,

 

 

ig add grid mygrid

 

Then run application using

ig start

This command will install all required modules and run the application. You will have application running as shown below:

This is all you need to do to update to latest version of Ignite UI CLI. I hope you find this post useful. Thanks for reading.

The Transformational Power of Deploying the Right Mobile Solution

FinJS London: The Webinar Surrounding Our OpenFin OS Support

$
0
0
Learn about Infragistics' support for capital market applications and high-volume financial charting with OpenFin OS and Angular. (read more)

Dynamically Load Angular Components

Hybrid Apps Offer Benefits Over Native Mobile Apps

$
0
0

Today, organizations are no longer asking themselves, ‘Do I need a mobile app?’ With more people than ever accessing information from their favorite clothing stores, booksellers, furniture retailers and more, there is no question that organizations need apps that can deliver a responsive, appealing user experience on devices.

The question, though, has shifted to ‘Do I need a mobile app or a browser app?’ Native apps require unique skill sets for writing to discreet platforms, and those apps have to be written over and over to run on each platform. Browser apps can work well on mobile devices but don’t allow developers to take advantages of the device’s features.


This month’s cover story in SD Times looks at the pros and cons of hybrid apps. In the piece, news editor Christina Cardoza writes:

“According to the Ionic Developer Survey 2017, hybrid app development is taking over. The report revealed that 32.7 percent of responding developers plan to abandon native app development in favor of hybrid. In addition, the survey found a nearly 700 percent decrease in developers building exclusively with native tools.

“A hybrid app is essentially a native app, Ionic’s CEO Max Lynch explained. Hybrid apps are downloaded from an app store similarly to native, and can access native feature such the GPS, camera, contacts, accelerometer and sensors. The difference is that native require proprietary or platform-specific languages such as Swift, Objective-C and Java, while hybrids utilize web technologies — JavaScript, HTML and CSS. By using a webview wrapper, such as Electron or Apache Cordova, which enables the app to call into the device’s native features, web developers can use their existing skill set, whereas in a native approach they would have to learn a new set of skills.”

Angular bridges gap between developers, designers

Quite often in application development, the code and business logic are written in one place, and the design is created in another. This disconnect had led to some pretty unusual applications that have CTA buttons in unexpected places, copy that’s too narrow or wide, art that overwhelms or that you need a magnifying glass to really understand.

The Angular team is looking to address that problem with Angular for Designers, introduced last month at the ng-conf in Salt Lake City, Utah.

As SD Times reported:

“Apps that users love to use, developers love to build,” said Stephen Fluin, developer advocate for Angular. “But we have been leaving out designers and I think they are a critical part of building experiences that users love to use.”

Fluin defines designers as “individuals who focus more on the user interface and user experience.” The reason why the team is taking a broad definition to designers is because a lot of designers define themselves in different ways, use different tools and have a variety of different skills, so the team did not want to leave anyone out.”

Angular looks to deliver solutions that don’t require designers to learn development tools, but focus on the designers’ job: ergonomic file formats, ability to create a single HTML file, adding new commands, and more.

Node.js announces first release in 10.x line

The release, which will offer Long Term Support, upgrades to OpenSSL 1.1.0, leveraging work to improve code quality cleanup and modernization, reports SD Times online and social media editor Jenna Sargent. In the article, Sargent writes:

“Node.js 10.0.0 is the seventh major release of the project since the launch of the Node.js Foundation in 2015,” said James Snell, Node.js release manager for 10.0.0. “This release continues the project’s commitment to delivering improved stability, performance, and reliability for all Node.js users. While there are a handful of new features, the standout changes in 10.0.0 are improvements to error handling and diagnostics that will improve the overall developer experience.”

A Comparison Between the Microsoft SharePoint Mobile App and Infragistics SharePlus:Simplicity and Customization

$
0
0

When determining the right mobile solution for your business, there are several considerations to make, including to ensure end user adoption and deployment success.In our last blog, we gave a brief overview of the major items to consider when moving towards a new mobile solution. This blog utilizes direct comparisons between Microsoft's SharePoint mobile app and Infragistics SharePlus to highlight the how a simple and customizable UX can reduce app abandonment.  

Simplicity: The One App vs. Two Apps User Experience 

SharePoint for iOS App Review: “I had high expectations for the app until I had a hard time getting to what I wanted. Keep getting annoying prompts for OneDrive to handle files.  Not deploying this company wide until a myriad of items get fixed." 

Microsoft has taken a multiple app approach to mobile file access. To access any files offline and online files located in other locations beyond favorites or recents, the user is pushed from SharePoint to OneDrive.  This requires the user to download, manage and navigate between two apps.  For the user, this creates a dissonant experience, with two incongruous looks and feels. This two-application experience leads to frustration and to low adoption rates for teams, as most users expect a fully integrated, one-stop solution.  

The SharePlus solution has been designed with simplicity in mind, providing one place and one simple and easy experience for mobile users to quickly find and access the files they need.  The SharePlus environment is fully integrated with SharePoint with no back and forth switch back between applications, allowing a user to find their relevant data with a few clicks with no worry about how the data might be displayed. 

Customizable: Mobile Workspaces 

SharePlus has also taken the concept of simplifying navigation to the next level with additional functionality that enables organizations to fully configure custom mobile workspaces and provide end users with curated content experiences. These mobile workspaces can be specifically tailored to meet mobile team needs providing one tap access to content. They are deployed using templates with no coding required to ensure deployment is also simple and near instantaneous.   

Ultimately, users have a vote too in their day-to-day product usage. If a solution doesn't meet the needs of your workers, success with deployment is going to drop. This is one of the major considerations when moving towards an enterprise-ready solution.  Other considerations, like the transformational power of the application and the use of powerful functionalities, are explored in our other app comparison blogs. If you're interested in experiencing the navigation experience for yourself, try out the SharePlus demo and see what a one-app mobility solution can do.  


Is JavaScript Changing Too Quickly?

$
0
0

One thing about software development: There are so many languages and tools to choose from. From desktop to browser-based and mobile, there’s a flavor for everything you’ll ever need. Yet some in our industry believe there is “JavaScript fatigue” happening. This, in a recent article in SD Times, is defined as the inability to keep up with all the tools and the constant changes in the developer ecosystem. A recent “State of JavaScript” report looks at all that’s changing and the impact of those changes.

JavaScript most widely used language

In the 2018 JetBrains survey, Java remains the most popular primary programming language, but JavaScript is the most used programming language overall.  For mobile, Kotlin might not yet be widely used, the but the survey showed that interest in the programming language is high. You can read the SD Times story here.

Angular for Designers initiative makes progress

At the community ng-conf last month, the Angular team at Google announced it is advancing work on Angular for Designers. As we reported in SD Times, the public launch remains months away, but the team is hard at work on a WYSIWYG prototyping tool that will give designers the ability to create this mockups without writing any code. Stephen Fluin, developer advocate for Angular at Google, lays it all out in this video from the conference.

Vue Vixens

Every Friday on sdtimes.com, we turn the spotlight on open source by selecting a project of the week. Earlier this month, we chose a community program with the mission of introducing women to JavaScript. As SD Times news editor Christina Cardoza reported, other communities for women in programming exist (Django Girls, ng-Girls and more), but Jen Looper, a developer advocate at Progress, saw there was a lack of community around Vue.js, a progressive JavaScript framework for building user interfaces to help scale web applications. Here’s a video describing the effort, including a message from vue.js creator Evan You, founder of Vue Technology.

A Comparison Between the Microsoft SharePoint Mobile App and Infragistics SharePlus: Transformational

$
0
0

This article in our Sharelus vs SharePoint comparison series explores the driving force behind a transformational enterprise mobility solution. mobility solution that harnesses the power of data and capture and sharing are the keys to streamlining your daily operations. Let's compare the transformational capabilities of the two apps.

Transformational: Capturing and Sharing Data On-the-Go 

SharePoint for iOS App Review: “Forget trying to upload event photos straight from your phone, because whenever the app tries to open your camera roll, it just exits out of the sub site you had to use 5 whole minutes to find…It is incredibly frustrating if you want to edit, upload, create a new file or anything else.” 

True competitive advantages are gained by enabling mobile teams to collect and share data while in the field. Construction site managers, for example, can electronically submit project checklists and document jobsite progress along with posted photos. Drivers working for transportation and distribution companies can capture inventory status complete with photos, timestamp, all GPS data from the road, and then instantly send this information back to the office. Field sales reps can also capture customer data to resolve customer issues to make the sale at customer locations. 

The SharePoint mobile app cannot provide this transformational functionality.  It displays only the default view and does not support any of the SharePoint views or meta data that have been created for curating content or capturing data into SharePoint lists. Any investment in view or list creation can’t be leveraged on mobile devices because of this limitation, and it is impossible for mobile users to capture and to share data from the field when offline.   

SharePlus enables mobile teams to use native views to capture data into SharePoint lists and instantly share it with the main office. This onsite data collection and sharing capability is available with or without network connectivity. The SharePlus app also perfectly integrates with the mobile device’s unique features, including the GPS tracker and camera. This allows users to post and to share photos and GPS information along with the collected data to keep their projects moving on time and on budget. SharePlus customized mobile workspaces also provide mobile teams with one tap access to the documents and list items to dramatically simplify mobile user navigation to data entry screens. 

Ideally, your mobile solution is one that also functions as a light data solution. You'll want quick, efficient access to your most important files at the right moments. When strong data share and capture go hand-in-hand with navigational ease and other powerful functionalities, the mobile solution will greatly increase workflow and productivity. If you'd like to experience the data capture, make sure to download the SharePlus demo for yourself and see how powerful it can be. You can also explore how important navigational ease and powerful functionality is to choosing the right mobility app for your teams, as covered in our other articles in our SharePlus vs SharePoint comparison series. 

Infragistics Team visited South Korea

$
0
0

As my previous entry, Infragistics Team visited South Korea last month partnering with BluePort.
It was the first time for us to visit the country and we had great conversations with developers in Korea.

We hosted Infragistics Dev Day between June 21 and 22 at the BluePort office. We split a day into 2 parts, Angular focused event and WPF focused event. We also had a repeated event in following day.

AM on June 21, 2018 - Angular focused event

We started with Infragistics overview by Jason Beres, Senior VP of Developer Tools:

Jason Beres

He talked about overview of Infragistics products and benefits mainly focusing on web controls. He showed grids and various types of charts and demonstrated performance of Ignite UI for Angular and participants were impressed with the speed and real time response. All attendees are developing or planning to develop with JavaScript/HTML5 and/or Angular.

Satoru Yamaguchi, Solution Consultant for Japan and APAC region hosted Ignite UI for Angular Hands On next.

Satoru Yamaguchi

He went through an overview of Ignite UI for Angular, then led a Hands On. Attendees learned how to build a material design based application using Infragistics Ignite UI for Angular components such as grid and chart. Most of the attendees were new to Angular, but they were able to complete the contents.

PM on June 21, AM on June 22, 2018 - WPF focused event

We knew WPF is very popular in South Korea and it's proven that the number of registrants exceeded limit very fast, so we decided to have a second day for the WPF event.

Again, Jason started with Infragistics overview, but focusing on WPF product we have been providing more than 10 years such as grid, charts, productivity tools we're offering.

Satoru hosted another Hands On for Ultimate UI for WPF, too. Like Angular focused event, attendees learned how to build a WPF application using Infragistics grid, chart, pivot, Excel engine, and some other controls. Infragistics WPF configurators were introduced for quicker and easier development. Many of them are Windows Forms users and a half of them have some experience with WPF. All of them were able to complete the contents!

WPF Day1

WPF Day2

Hands On materials are available on GitHub here, please try it out and let us know what you think.

GitHub - Angular Hands On

GitHub - WPF Hands On

Round table with Korea MVPs!

On the last day, Infragistics Team visited Microsoft Korea Office and had a round table with Korea MVP. We learned a lot of insights and got improvement ideas. We really appreciate everyone to support our visit and spent time with us!

We will be back to Korea soon and I hope I can visit there next time! Let's keep in touch!

Infragistics Dev Day

Step by Step for Creating Your First Angular Element

$
0
0

Angular Elements allow us to create reusable Angular components, which can be used outside of the Angular application. You can use an Angular Element in any other application such as normal HTML, React, etc.  Essentially, Angular Elements are normal components, which are packaged as Custom Elements. You can learn more about Custom Elements here.

Angular Elements are reusable components, which can be used outside Angular.  You can learn more about

We will keep things simple in this post and, in a step by step manner, learn to create a basic Angular Element. So, let us get started.

Step 1: Installation

Create a new project using Angular CLI 

ng new demo1

Once the project is created, change directory to demo1 and install Angular Elements. For that, run an npm command, as shown below:

npm install @angular/elements

To work with older browsers, we need polyfill. So, let us install that also as shown below:

npm install @webcomponents/custom-elements

 After installing polyfill, open polyfills.ts file and add these two entries:

import '@webcomponents/custom-elements/src/native-shim';
import '@webcomponents/custom-elements/custom-elements.min';

Step 2: Create the Component

In this step, we will create a reusable component, which would be used as an Angular Element.

   import { Component, Input } from '@angular/core';
 
  @Component({
      selector: 'app-message',
      template: `
 <h1 style='text-center'>{{title}}</h1>
  <h2>hey {{name}} loving Angular Elements {{answer}}</h2>
`,
      styles: ['h2 {color:red;}']
  })
  export class MessageComponent {
      title = 'Angular Elements';
      @Input() name: string;
      @Input() answer: string;
  }

MessageComponent is a very simple component with two properties decorated with the @Input() decorator.

Step 3: Register the Component

 To register a component to be used as an Angular Element, we need to perform following tasks:

  • Import component.
  • Pass it in declarations array.
  • Pass component in entryComponents array.
  • Do not pass any component in bootstrap array.
import { BrowserModule } from '@angular/platform-browser';
 import { NgModule } from '@angular/core';
 import { MessageComponent } from './message.component';
 
 @NgModule({
     declarations: [
         MessageComponent
     ],
     imports: [
         BrowserModule
     ],
     providers: [],
     bootstrap: [],
     entryComponents: [MessageComponent]
 })
 export class AppModule {
 
 }

We do not need to bootstrap custom elements. They will be created automatically when added to the DOM and destroyed when removed from the DOM, however, they have to created somehow hence we are adding them in entryComponents array. You must be knowing this property from dynamic component.

Step 4: Create Element from the component

 We need to invoke createCustomElement to create a custom element from an Angular Component. To do that, first import following items in angular.module.ts

import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';

After importing required modules in the AppModule, we need to create custom element as shown in the listing below. Also, we are manually calling ngDoBootstrap.

export class AppModule {
 
      constructor(private injector: Injector) {
          const customElement = createCustomElement(MessageComponent, { injector });
          customElements.define('app-message', customElement);
      }
 
      ngDoBootstrap() {
 
      }
  }

Step 5: Use Custom Element

Ideally, we will use the custom element in any external html file. In a further article, we will cover that. To use created custom element in index.html of same angular application, just place it in body, as shown below:

<body>        <!-- <app-root></app-root> -->        <app-message name="dj" answer="yes"></app-message></body>

Now run the application using command ng serve and you should have custom element rendered, as shown in below image:

Therefore, we can conclude that to work with Angular Custom Element, we need to perform following steps:

  1. Install @angular/elements
  2. Create component
  3. Register component in entryComponent
  4. Invoke createElement to create custom element
  5. Use it on html

 I hope you find this post useful. Thanks for reading.  If you like this post, please share it. Also, if you have not checked out Infragistics Ignite UI for Angular Components, be sure to do so! They have 30+ material based Angular components to help you code web apps faster.

Pivot Tables Made Easy

$
0
0

If you don’t know what they are, how to use them, why they are useful, or what they even do, pivot tables can become scary and complex. You’ll soon find that a pivot table is a great way to quickly summarize, analyze, explore, and present your data.

ReportPlus, built by user experience experts, makes pivoting your data easy with an intuitive drag and drop experience. The pivot table is broken out into four sections: Values, Rows, Columns and Filters:

You will see that as you start dragging fields into a corresponding section that the data being displayed will instantly update. 

Values

This location is where you will drop your value field upon which you want your visualization to be built. By default, the field that you place in the values section will be summarized as a sum. If your field is a text field, ReportPlus will detect this and display your data as count.

You can see here that, by dragging Sales over to my values section, ReportPlus summarized my data:

If a value is all you wish to display, you can display your value in the form of a gauge. By clicking on the sales field, I am prompted with options to customize the value by changing the aggregation, formatting, sorting and filtering. You have these options and more in any field that you bring over.

Rows

This section is where you would drop the field that you want to correspond to the x-axes of your visualization. So, if I change my visualization to a column chart and drag a date field over to rows, you will see sales by month.

Columns

Regarding the columns section, here are the fields that you would have appear in your chart legend or the columns of a table, etc.

  

Filters

The filters section allows you to filter and slice your data based on a certain field. So, if I wanted to see sales by month per product, but I only wanted to see the deal types that were subscriptions, I would pull deal type over to the filters section. Then, I can click on the field to select which value(s) I want to filter by:  

To see how you can easily pivot your data in action with R+, check out this video. If you like the ease and functionality behind these pivot tables, consider taking a closer look at ReportPlus. It’s our answer to true self-service BI, allowing you to better visualize and understand your significant data for faster decision-making.

Demystifying Angular Unit Tests: Part 2

$
0
0

Part 2: The Anatomy of an Angular Spec File

By: Jared Fineman

The more things change, the more they stay the same; this adage definitely applies to unit testing. Although we’ve advanced greatly in the world of software development, the fundamentals remain the same. Certain things like AAA, Arrange, Act and Assert will always apply, however, we must learn how to think of them within the world of Angular.

In the previous article, we discussed setting up the infrastructure needed in an Angular Unit Testing Module. So for this article, I’d like to focus on the components that make up your typical Angular Spec File and provide the implementation of the age old concepts of AAA.

In the Arrange portion of our unit test, Angular, leveraging the Jasmine unit testing library, will first describe the component we wish to test by utilizing the describe function, as illustrated below. It’s important to utilize a descriptive name, as this will make reading the results from your unit tests a lot easier.

describe('AppComponent', () => {

Moving on to the Arrange section of our file spec, we utilize the beforeEach function to initialize any configurations that will be needed across all the unit tests in the file. Unique to Angular, however, is the TestBed class, which provides the essential ingredients needed for simulating the construction and initiation of our Angular Module.

beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent,
      ],
      imports: [RouterTestingModule],
      providers: [
],
    }).compileComponents();
  }));

 If you’ll notice, we are using the configureTestingModule method of the TestBed class to initialize our configurations. If we look at the source code, the TestBed class provides additional methods for testing that can be very useful.

    static compileComponents(): Promise<any>;
    static overrideComponent(component: Type<any>, override: MetadataOverride<Component>): typeof TestBed;
    static overrideTemplate(component: Type<any>, template: string): typeof TestBed;

As their names imply, the above methods can be used to override functionality contained within your module. This may be useful in a case where you want to provide mock data to your component, but your component is coupled with a particular provider; overrideComponent would then give the ability to pass in a fake provider service to inject the mock data.

Some additional things to take note of in the previous code snippet are the RouterTestingModule and the compileComponents function. The RouterTestingModule can be used as a substitute for the usual RouterModule and simulates route navigation without having to actually change url locations. In addition, the RouterTestingModule has a method, withRoutes, that accepts a parameter value of fake routes, which can be useful in various testing scenarios. The compileComponents function is necessary when running your unit tests with a library other than angular-cli. When using angular-cli, however, your unit test code is compiled automatically during the initialization stage.

The Act section of unit testing is where we actually setup our individual unit tests and should look similar to the code below:

  it('should render title in a h1 tag', async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;

The createComponentmethod is responsible for creating a copy of the root of our component and returns an object of type ComponentFixture. The fixture of an Angular Unit Test is crucial in that it helps manage and simulate the component’s life cycle. By calling the detectChanges method, the component will detect changes in its environment and bind all of its properties. Keep in mind that our unit tests exist outside the domain of the Angular component lifecycle, therefore, in order for any change to be detected we must first call the detectChanges method.

A closer look at the ComponentFixture class reveals a property of type DebugElement.

export declare class DebugElement extends DebugNode {
    properties: {
        [key: string]: any;
    };
    attributes: {
        [key: string]: string | null;
    };
    classes: {
        [key: string]: boolean;
    };
    styles: {
        [key: string]: string | null;
    };
    nativeElement: any;
    query(predicate: Predicate<DebugElement>): DebugElement;
    queryAll(predicate: Predicate<DebugElement>): DebugElement[];
    triggerEventHandler(eventName: string, eventObj: any): void;

First to notice is that the DebugElement class contains properties such as, properties, attributes, classes, styles that help streamline our unit tests by giving us a wealth of information about our component at our fingertips. The next step is the triggerEventHandler, this method is crucial for simulating DOM events that will be picked up by our component’s event listeners. Last, but not least, is the query method, by far my favorite.

Similar to jQuery, the query method is able to able to search through the DOM and return matching elements. The main difference, and advantage, in its functionality is that the return value is not merely a collection of DOM elements, but of DebugElement objects, making it easier to test nested components. In addition, the query method accepts a parameter of type Predicate<DebugElement>, meaning we can query the DOM using any of the properties found in the DebugElement class.

If that weren’t enough, Angular has provided a class called By, which has further methods to ease the construction of Predicate objects for use in our queries. Below is an illustration, taken from the Angular testing guide, of some examples of this class:

const h2        = fixture.debugElement.query(By.css('h2'));

const directive = fixture.debugElement.query(By.directive(HighlightDirective));

Finally, the last step of AAA, Assert, should look similar to the below:

expect(app.title).toEqual('app');

This is very similar to a typical Jasmine unit test, except we see the power of the Angular unit testing library, as we are directly accessing the title property of the component.

If you like this post, please like it and share it. In addition, if you haven’t checked out Infragistics Ignite UI for Angular, be sure to do so! They’ve got 50+ material-based Angular components to help you code speedy web apps faster.

Microsoft's Build 2018 and Everything That We Learned

$
0
0

With throngs of people chattering and rampant idea-sharing in the air, Microsoft's 2018 Build conference represented the sheer eagerness attendees had regarding the futurology of tech. The Washington State Convention Center packed upwards of 7,000 attendees, ensuring that lectures and sessions would be busy, full of learning, and conversant. With Satya Nadella, the CEO of Microsoft, dominating the keynote speech, the giant crowd was witness to the overarching ideas behind the conference: responsibility in computer-learning, the advent of Visual Studio Code Live, the hallmarks of Azure, and the cutting-edge opportunities we have torevolutionize work through mixed reality. As Nadella noted, "The world is becoming a computer," and he's right. 

So, What Did We See? 

Between the Expo Hall and the sessions dotting the building's landscape, major players in the industry were showcasing their newest wares and ideas. From GitHub to LinkedIn and from Docker to Citrix, there was information abound for attendees to access. With sessions held about Kubernetes, Azure, Visual Studio Code Live, machine-learning, Microsoft Graph, the HoloLens, and more, Build aimed to commandin the area of thought-leadership.  

At the Infragistics booth found near the Client & Web area, we spent three successful days demoing portions of our new Infragisitcs Ultimate 18.1 release. While showing off our updates to the fastest Angular data grid, financial charts, and improved spreadsheet functions, booth attendees were able to join in on our #PinItToWinIt campaign at the Expo and on Twitter. The campaign encouraged attendees to affix the Infragistics pin, and this put them in the running to earn one of our twenty giveaway sweatshirts or our large prize, Beats headphones.  

How Were the Conversations? 

The team found themselves having lengthy discussions about our high-speed Angular data grid features, showcasing the smooth rendering of large-scale data sets and the financial charting capabilities. With a healthy mix of current and new customers arriving to talk, excitement rested primarily on the power of our material-based Angular components. When not discussing Angular, many also came to explore and learn about our WPF and Windows Forms features, particularly for our work with the Excel engine updates. There was also a strong showing of those interested in our enterprise management products, with ReportPlus Embedded dominating the space due to its easy data visuals and cross-platforming.  

Where are We Going from Here? 

Moving forward for 2018, Infragistics is going to set its eyes on the area of rapid application development, promoting WYSIWYG and UI kits for web and mobile app building and delivering a design-to-code workflow across Indigo Studio and Ignite UI. From this design-to-code workflow, we'll have code generation for Flutter and Angular, adding to our innovative features surrounding our Angular grid and charts components.  

Excited to Learn More? 

We have an extensive list of products that make web, desktop, and mobile application development far easier and more streamlined. Since we've spoken so much about Angular recently, be sure to take a look at ourIgnite UI for Angular and the Ignite UI for Angular CLI and get to working with the fastest Angular data grid. On top of that, consider making your way to our popular enterprise management tool, ReportPlus Embedded. It enables businesses to create rich, beautiful data visualizations to accelerate ROI and to bring BI to life. Plus, if you're interested in a large-scale solution, learn about ourUltimate developer's toolkit which gives you a single platform for UX design and enterprise application development.


Creating a Population Pyramid Chart using Stacked Bar Charts with ReportPlus

$
0
0

Pyramid charts are very popular visualizations when working with demographics as they are an easy way to show the age and male/female composition of a given country. While line charts are very common when describing the growth scale of any population, pyramids are preferred as they are ideal to detect any changes or significant differences.

Population Chart

What are Stacked Charts?

Stacked charts are basically bar, area, or column charts that do not overlap because they are placed on top of each other. Stacked bars, for example, present information in a horizontal comparison and are meant to help users visualize how each piece of data correlates to the whole data set.

StackedChartSample

ReportPlus steps up to the plate by adding a new feature for users: the ability to present stacked charts with a percentage distribution instead of the default 0-100 scale.

Why not use a Bar Chart instead?

In the case above, where what’s being compared is a set of aging ranges, bar charts would only be helpful when representing data by year. Take a look at the data below: the first one is a bar chart plotted by year, and the second one is the equivalent to the stacked chart above.

If you really need to see your data broken down by the exact dates, bar charts just aren’t the correct fit.

How this relates to Population Pyramids

Population pyramids usually display not one data series, but two: age and female/male ratio. You’ll therefore need to use a chart that supports two or more series.

Sample Population Data

Let us consider the following figures to create the visualization in the screenshot above. These include the age ranges for Seattle inhabitants along with the male/female population ratio.

When we create the widget in ReportPlus and choose the Stacked Bar visualization, the data will be plotted in the following way:

In order to create a pyramid, we’ll need the values for male and female to point in two different directions. Therefore, let’s create a calculated field that displays the opposite of the male population:

Then, hide your original “Male” field by toggling the “Is Visible” slider.

Your visualization will now look like the following one:

Formatting your Data

If you want or need, you can format the negative values in a different way by changing the “Negative number format”.

If you want the pyramid to show the values from highest to lowest, change one of the genders’ Sorting to “Asc”:

By default, the theme will be set to “The Blues”. Change your theme to any of ReportPlus’ more than 20 themes if you want to have more contrast between the figures.

Interested in trying this out?

Download a free trial of ReportPlus Desktop or ReportPlus iOS now, or contact us to get this ready for you!

Demystifying Angular Unit Tests: Part 3

$
0
0

Interacting with Forms

By: Jared Fineman

When we think of forms, we may have visions of a stack of papers, piled on a waiting room table in a doctor’s office. However distant web forms may be from that concept, in terms of tediousness, a lot remains the same. Whether it be laying them out, styling them, or simply binding them, forms can be a chore in their own unique way and nothing changes when it comes to unit testing. Thankfully, by leveraging the Angular Unit Testing Library, we can streamline the process.

Let’s start by examining a unit test for the completion of a form:

it('should activate done button when complete’, async(() => {
  const fixture = TestBed.createComponent(LocationOptionsComponent);

  fixture.detectChanges(false);

  let inputs = fixture.debugElement
.queryAll(By.css('input.form-ontrol:not(.filter-input)'));

  let combos = fixture.debugElement.queryAll(By.directive(TypeaheadComponent));
        
  let doneBtn = fixture.debugElement
.queryAll(By.css('.star-grid-header-buttoncontainer input'))[1];

  ...

As we can see from the description of the unit test, the done button should only become active after the form is in a state of completion. We begin by querying the created component in order to find the form and all of its elements.

One thing to note is the power of the queryAll method of the Angular library; it is able to use a complex css selector to return a collection of DebugElement objects that represent the inputs of the form. Alternatively, the queryAll method can be passed a value type of directive or component as a parameter and it will return all corresponding matches. For more information about the query method, please see my previous article titled, "Demystifying Angular Unit Tests: Part 2: The Anatomy of an Angular Spec File".

At this point in the unit test, we have a collection of all the various inputs, some simple and others more complex, like drop-down menus or autocomplete fields. The challenge here is being able to simulate interactions with each component properly in order to test the various form dynamics. The following sections will illustrate how we locate and interact with each particular field, using the Angular library:

 optionNameInput.nativeElement['value'] = 'Testing';
 optionNameInput.nativeElement.dispatchEvent(new Event('input'));

We begin by examining a variable named optionNameInput in order to gain a better understanding behind some of the key concepts in unit testing forms. The optionNameInput, as well as the other field variables, are all of type DebugElement, a powerful class for unit testing. This class has a property called nativeElement, by which we can directly access and manipulate the field value in the DOM. This is insufficient, however, to activate Angular’s event detection. In order to do that, we will need to simulate an input event using the dispatchEvent method; doing so will then trigger data binding, validation, as well as any event listeners.

We have just successfully simulated an input event for our unit test, but how would we handle something more complex like selecting an option from a drop-down menu or an autocomplete field?

optionTypeInput.nativeElement.dispatchEvent(new Event('input'));
 activeInput.nativeElement.dispatchEvent(new Event('input'));

Similar to the input field, our autocomplete variables, optionTypeCombo and activeCombo, require an event to be fired in order to activate change detection, and in turn, expand the option menu. We handle this by first calling the dispatchEvent method, followed by a strange call to a method called whenStable.

fixture.whenStable().then(() => { ... }

As described in the Angular site documentation, whenStable is responsible for returning a promise after the completion of an asynchronous event. In order for us to catch the event of the autocomplete menu opening, we need to nest the continuation of our code within the returned promise of the whenStable call.

let locationOption = optionTypeCombo.query(By.css('button')).nativeElement;
    locationOption.dispatchEvent(new Event('click'));

let activeOption = activeCombo.query(By.css('button')).nativeElement;
    activeOption.dispatchEvent(new Event('click'));

Now that it has open, we are ready to make a selection from the autocomplete menu. Using the query method of the DebugElement object, we are able to find the first autocomplete field option, represented by a button element. Once again, we call the dispatchEvent method, but this time passing in a click event, to simulate selecting the first option.

fixture.detectChanges();

 expect(doneBtn.properties['disabled']).toBe(false);

After a quick call to detectChanges, which starts the Angular detection process, we are ready to check if the form is in a complete state, our primary indicator being an active done button. We have already queried and saved the done button as a variable of type DebugElement; using its properties value, we can now detect the disabled status of our button.

If you like this post, please like it and share it. In addition, if you haven’t checked out Infragistics Ignite UI for Angular, be sure to do so! They’ve got 50+ Material-based Angular components to help you code speedy web apps faster.

Understating Angular Change Detection with example

$
0
0

Change Detection means updating the DOM whenever data is changed. Angular provides two strategies for Change Detection.

  1. Default strategy
  2. onPush strategy

In default strategy, whenever any data is mutated or changed, Angular will run change detector to update the DOM. In onPush strategy, Angular will only run change detector only when new reference is passed to @Input() data.

To update the DOM with updated data, Angular provides its own change detector to each component, which is responsible to detect change and update the DOM. 

 Let us say we have a MessageComponent as listed below:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-message',
  template: `
    <h2>
    Hey {{person.firstname}} {{person.lastname}} ! 
    </h2>
    `
})
export class MessageComponent {

  @Input() person;
}

In addition, we are using MessageComponent inside AppComponent as below,

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'app-root',
    template: `
  <app-message [person]='p'></app-message>
  <button (click)='changeName()'>Change Name</button>
  `
})
export class AppComponent implements OnInit {
    p: any;
    ngOnInit(): void {
        this.p = {
            firstname: 'Brad',
            lastname: 'Cooper'        };
    }
}

Let us talk through the code: all we are doing is using MessageComponent as child inside AppComponent and setting value of person using the property binding. At this point on running the application, you will get name printed as output.

Next, let us go ahead and update firstname property on the button click in AppComponent class below:

changeName() {
  
    this.p.firstname = 'Foo';
}

As soon as we changed the property of mutable object P, Angular fires the change detector to make sure that the DOM (or view) is in sync with the model (in this case object p). For each property changes, Angular change detector will traverse the component tree and update the DOM.

Let us start with understanding about component tree. An Angular application can be seen as a component tree. It starts with a root component and then go through to child components. In Angular, data flows from top to bottom in the component tree.

Whenever @Input type property will be changed, Angular change detector will start form the root component and traverse all child components to update the DOM. Any changes in primitive type’s property will cause Angular change detection to detect the change and update the DOM.

In above code snippet, you will find that on click of the button, the first name in the model will be changed. Then, change detection will be fired to traverse from root to bottom to update the view in MessageComponent.

There could be various reasons of Angular change detector to come into action and start traversing the component tree. They are:

  1. Events fired such as button click, etc.
  2. AJAX call or XHR requests
  3. Use of JavaScript timer functions such as setTimeOut , SetInterval

Now, as you see,  a single property change can cause change detector to traverse through the whole component tree. Traversing and change detection is a heavy process, which may cause performance degradation of application. Imagine that there are thousands of components in the tree and mutation of any data property can cause change detector to traverse all thousand components to update the DOM. To avoid this, there could be scenario when you may want to instruct Angular that when change detector should run for a component and its subtree, you can instruct a component’s change detector to run only when object references changes instead of mutation of any property by choosing onPushChangeDetection strategy.

 You may wish to instruct Angular to run change detection on components and their sub-tree only when new references are passed to them versus when data is simply mutated by setting change detection strategy to onPush.

Let us go back to our example where we are passing object to MessageComponent. In the last example, we just changed firstname property and that causes change detector to run and to update the view of MessageComponent. However, now we want change detector to only run when reference of passed object is changed instead of just a property value. To do that let us modify MessageComponent to use OnPush ChangeDetection strategy. To do this set changeDetection property of @Component decorator to ChangeDetectionStrategy.OnPush as shown in listing below:

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';

@Component({
    selector: 'app-message',
    changeDetection: ChangeDetectionStrategy.OnPush,
    template: `
    <h2>
    Hey {{person.firstname}} {{person.lastname}} !
    </h2>
    `
})
export class MessageComponent {

    @Input() person;
}

At this point when you run the application, on click event of the button in AppComponent change detector will not run for MessageComponent, as only a property is being changed and reference is not changing. Since change detection strategy is set to onPush, now change detector will only run when reference of @Input property is changed.

changeName() {
  
    this.p = {
        firstname: 'Foo',
        lastname: 'Kooper'    };
}

In the above code snippet, we are changing reference of object instead of just mutating just one property. Now when you run application, you will find on the click of the button that the DOM is being updated with new value.

By using onPush Change Detection, Angular will only check the tree if the reference passed to the component is changed instead of some property changed in the object. We can summarize that, and Use Immutable Object with onPush Change Detection to improve performance and run the change detector for component tree when object reference is changed.

 We can further improve performance by using RxJS Observables because they emit new values without changing the reference of the object. We can subscribe to the observable for new value and then manually run ChangeDetector.

 Let us modify AppComponent to pass an observable to MessageComponent.

import { Component, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Component({
    selector: 'app-root',
    template: `
  <app-message [person]='data'></app-message>
  <button (click)='changeName()'>Change Name</button>
  `
})
export class AppComponent implements OnInit {
    p: any;
    data: any;
    ngOnInit(): void {
        this.p = {
            firstname: 'Brad',
            lastname: 'Cooper'        };
        this.data = new BehaviorSubject(this.p);
    }

    changeName() {

        this.p = {
            firstname: 'Foo',
            lastname: 'Kooper'        };
        this.data.next(this.p);
    }
}

In the code, we are using BehaviorSubject to emit next value as an observable to the MessageComponent. We have imported BehaviorSubject from RxJS and wrapped object p inside it to create an observable. On the click event of the button, it’s fetching the next value in observable stream and passing to MessageComponent.

 In the MessageComponent, we have to subscribe to the person to read the data.

@Input() person: Observable<any>;
_data;

ngOnInit(){
    
    this.person.subscribe(data => {
        this._data = data;

    });
}

Now, on click of the button, a new value is being created, however, a new reference is not being created as object is an observable object.  Since a new reference is not created, due to onPush ChangeStrategy, Angular is not doing change detection. In this scenario, to update the DOM with new value of observable, we have to manually call the change detector as shown below:

export class MessageComponent implements OnInit {

    @Input() person: Observable<any>;
    _data;

    constructor(private cd: ChangeDetectorRef) { }
    ngOnInit() {

        this.person.subscribe(data => {
            this._data = data;
            this.cd.markForCheck();
        });
    }
}

We have imported ChangeDetectorRef service and injected it, and then calling markForCheck() manually to cause change detector to run each time observable emits a new value.  Now when you run application, and click on button, observable will emit new value and change detector will update the DOM also, even though a new reference is not getting created.

To summarize:

  1. If Angular ChangeDetector is set to default then for any change in any model property, Angular will run change detection traversing component tree to update the DOM.
  2. If Angular ChangeDetetor is set to onPush then Angular will run change detector only when new reference is being passed to the component.
  3. If observable is passed to the onPush change detector strategy enabled component then Angular ChangeDetctor has to be called manually to update the DOM.

 I hope you find this post useful. Thanks for reading.  If you like this post, please share it. Also, if you have not checked out Infragistics Ignite UI for Angular Components, be sure to do so! They have 30+ material based Angular components to help you code web apps faster.

Learn WPF! Learn Angular! "Infragistics Dev Day" in Korea with BluePort

$
0
0

I am excited to announce the first event in Korea and we invite developers in Korea!

Jason Beres, Sr. VP of Developer Tools and Satoru Yamaguchi, Solution Consultant will be visiting Seoul and they are going to introduce our latest products and provide free hands-on sessions for developers who are interested in building Modern Desktop and Web Applications using WPF and Angular.

Event Overview:

Host

Infragistics, Inc. / BluePort

Date

Thursday, Jun 21, 2018 (8:30 am to 12:00 pm / 1:30 pm to 5:00 pm)
Friday, June 22, 2018 (8:30 am to 12:00 pm)

Location

BluePort seminar room (9F Sangkyung Bldg, 120-gil, Teheran-ro, Gangnam-gu, Seoul)

http://www.blueport.co.kr/company/location.asp

Capacity

Morning Session (8:30 am to 12:00 pm) - Infragistics Ignite UI for Angular hands-on (28 persons)

Afternoon Session (1:30 pm to 5:00 pm) - Infragistics WPF hands-on (28 persons)

Admission Fee

Free

Contact: BluePort (02-569-3712 / sales@blueport.co.kr)

* English to Korean translation is provided

You can find detailed schedule and agenda here (Korean).

Registration:

There are two sessions on the day. Please pick one of them or both to sign up. (Edit on Jun 5th: since we have many registrants on the WPF session on June 21, we're opening up another session on June 22!)

June 21, 2018 - Morning Session - Angular

June 21, 2018 - Afternoon Session - WPF

June 22, 2018 - Morning Session - WPF

We are looking forward to seeing you all in Korea!

Ignite UI for Angular

Ensuring Customer Engagement with UX Research

$
0
0

While one might reasonably argue that sales is the lifeblood of any organization (especially if you’re responsible for reporting on P&L), customer engagement is, at a minimum, a major contributing factor. What should a business do then, when it is interested in creating or improving the level of engagement between their customers and themselves?

Traditional Problem

When the primary “product” consists of services, businesses create applications that they believe will meet the needs of their users. With the best of intentions, meetings are held, decisions are made, requirements are gathered, and code is written. To much internal fanfare, the application is released, and confident product owners wait anxiously, hoping for large scale engagement. To ensure customers are aware of the application’s existence, marketing talent is brought to bear - mail is sent out, press releases published, conferences attended, and t-shirts given away.

Traditional Result

What tends to happen next is all too common. The application, which met the needs of the business, and seemed like it should have met the needs of customers, didn’t. For some reason, users were uninterested, downloads dropped to the point that reporting on them became awkward, and eventually, the application stopped being supported and faded away. Why did this happen?

User Experience Solution

Contrary to what might seem the obvious solution, the key to driving large scale engagement is not creating a method by which users tell the business what they want. While this might be sufficient to drive incremental improvement, users are only able to articulate their obvious needs: “I want access to my services,” “I want to be able to pay my bill,” “Make it easy for me to see my coverage details.” These are all fine and obvious bits of functionality that users believe they want, but there is another set of requirements – latent requirements – that define features and functionality that will improve users’ lives in ways they cannot describe or request.

User Experience Research

The next question is, since users aren’t able to articulate their latent requirements, how do we know they exist? Assuming they exist, how can we hope to define them? The answer to both questions is User Experience Research. By employing on-site observations (a technique known as shadowing) and intelligent interviewing (a technique known as contextual inquiries), an experienced UX team is able to identify key user groups, define existing workflows, task frequency, significant bottlenecks and problem areas, device usage, etc., essentially inferring users’ latent requirements. Based on this understanding, they can coordinate this information into a unified set of stated and latent requirements, completely defining the problem areas within a user’s professional environment. This coordinated set of requirements defines the space within which users are willing to engage with the business. The level of engagement, therefore, is limited only to the degree that the solution resolves users’ problems.

User Experience Process & Deliverables

I’ve made some gross assumptions to show what such a research project might look like for a B:B application, such as an insurance application designed for medical professionals. Please keep in mind that any or all of these can be modified, and need not happen sequentially, depending on circumstances and business needs.

Small Office Research (3 people)

  • UX team onsite for 2 days
  • One day to coordinate findings

Medium Office Research (10 people)

  • UX team onsite for 4 days
  • Two days to coordinate findings

 Large Office Research (10+ people)

  • UX team onsite for 8 days
  • Three days to coordinate findings

 Deliverables

  • User Profiles/Personas
  • Workflows/Journey Maps
  • Informational Needs by User Type
  • Frequency of Use Metrics
  • Recommended Application Formats (web, mobile web, native web)
  • Application Wireframes
  • Full Aesthetic Designs
  • Front-End Development

The UX process is almost infinitely malleable. Ultimately, it comes down to understanding the risks associated with how you spend your research dollars, the experience of your UX team, and the relationship between time, money, and representative sample size. Customer engagement is about proactively understanding what customers need and how to make it available at the right time, in the most useful format, not about reactively working through a list of feature requests.

Design at Infragistics

Here at Infragistics Consulting, we pride ourselves on delivering thoughtful and useful design. Getting the job done isn't the same as getting the job done well and we sweat the small stuff because it matters. Let us show you how we can help by contacting us at services@infragistics.com.

Viewing all 2223 articles
Browse latest View live


Latest Images