Recent Blogs

AvatarByRashid Aziz

Sharing Office 365 Files & Folders with People outside your Organisation

If you perform work that involves sharing documents or collaborating directly with vendors, clients, or customers, then you might want to share content on your Team site or OneDrive for Business with people outside your organisation who do not have licenses for your Office 365 Small Business subscription.

You can share individual documents by inviting external users to sign in to your site using a Microsoft account or work or school account.

Here’s how you share files or folders in SharePoint:

  1. Select the file or folder you want to share, and then select Share

Click “People in your Organisation” dropdown and select Specific people (gives access only to the people you specify, although other people may already have access. If people forward the sharing invitation, only people who already have access to the item, should be able to use the link.)

By default, Allow editing is turned on. To only view your files, uncheck the checkbox.

When you’re done, click Apply.

Enter the email addresses of the people you want to share with and a message, if you want. When you’re ready to send the link, click Send.

AvatarByRashid Aziz

Microsoft Flow using Office 365 E3 Developer Plan

I have recently came across an issue. I was trying to do proof of concept project for one of my client. I tried to create Microsoft Flow using my Office 365 E3 Developer subscription. The flow created successfully but when I ran it throws the following error.

Start an Approval

The request failed. Error code: ‘CommonDataModelNamespaceNotProvisioned’. Error Message: ‘A Common Data Service database has not been provisioned for environment ‘Default-535dc980-ce8a-49fc-8f50-9b930035e176′, or is currently being provisioned.’

Condition

ActionConditionFailed. The execution of template action ‘Condition’ is skipped: the ‘runAfter’ condition for action ‘Start_an_approval’ is not satisfied. Expected status values ‘Succeeded’ and actual value ‘Failed’.

I tried to create Common data Service from Power app but “Environments” tab was not available under PowerApp admin portal.

After talking with Office 365 support people they made it clear that Environments and Common Data Service database cannot be created under Enterprise E3 developer Plan. My question is then, how a developer can build and test flows using Office 365 E3 developer plan?

AvatarByRashid Aziz

Nintex Workflow: How to get approved by Person name from a group task

Quite often it is necessary to get the name of the person who approved /rejected the task for auditing purpose or to display history as per business requirements. Imagine a Nintex workflow task is assigned to a group called “Legal Team. The task only needs to be approved by one person.  Nintex workflows provide out of the box variable to hold the approver name called “Last Task Respondent”. But if the task is assigned to a group rather than individuals, this variable will only store group name instead of the individual user name who approved it.  I came across this problem recently.
This left me with only one option, which is to extract the task approver person name from the “Approver Comments” common reference variable

In my case the approver comments looks like the below string. The task was assigned to “Legal Team” and approved by “Rashid Aziz” with some comments.

Approver Comments: Legal Team (Approve) 4/26/2016 10:20 AM – 4/26/2016 10:20 AM (Rashid Aziz) the approvers comments

The next steps will explain how to extract the approver name from above “Approver Comments” string

Workaround
Create three workflow variables

 

Note: Set “ApproverCollNumberIndex” value to 1. I will explain later why you need this to be set. 

Now create two operation actions under task “Approve” branch
1. Regular expression
2. Collection operation

 Double click on regular expression action and set the fields as below and store the results inside “ApprovedbyTextCollection”

Pattern: (?<=\()(.*?)(?=\))
The above pattern will extract the data within the brackets and will save it to result collection.
The collection will contain task outcome and approver name separated by semi colon e.g. “Approve;Rashid Aziz;”

Now, next step is to retrieve the approver name from the “ApprovedByTextCollection” collection.  The collection values are separated with semi colon and starts with index 0. The approver name is at index 1. This is why we set the “ApproveCollNumIndex” variable default value to 1.
The final step is to configure the Collection operation action as appear below. Set the index value to “ApproverCollNumIndex” variable (we set this default to 1) and store the results into our final variable “ApprovedByName”.

The Workflow variable “ApprovedByName” contain the task approver’s name at last. This variable value can now be stored separately as per business requirements. In my case I had to store approver name with date task submitted and date task approved date in a separate list fields and displayed them on the form in a more readable table format.

Happy no code solutions 

AvatarByRashid Aziz

SharePoint Hosted App to retrieve local weather information

In one of my previous post I explained how to get current user locale information like city, country, latitude, longitude, IP address using SharePoint hosted app. In this post, I have taken one further step to get the weather information of current logged in user’s location.

Follow the below steps to achieve the same results.

Create new SharePoint hosted app project inside visual studio.

Edit the “app.js” file and replace the code with below code. Remember to update the APIKey variable value in below code. You can get new APIKey from https://developer.forecast.io/register, and it is free.

jQuery.ajax({

    url: '//freegeoip.net/json/',

    type: 'POST',

    dataType: 'jsonp',

    success: function (location) {

        jQuery('#city').html(location.city);

        jQuery('#longitude').html(location.longitude);

        jQuery('#latitude').html(location.latitude);

        jQuery('#country-name').html(location.country_name);

        GetWeatherInfo(location.latitude, location.longitude);

    }

});

function GetWeatherInfo(lati, longi)

{

    var APIkey = 'API Key'  // Get a new key from https://developer.forecast.io/register and it is free

    var urlForecast = 'https://api.forecast.io/forecast/';

    var unit = 'si'; // "si" is shortcut for Celsius and "us" is shortcut for Fahrenheit

    jQuery.ajax({

        url: urlForecast + APIkey + "/" + lati + "," + longi + "?callback=?&units=" + unit ,

        type: 'GET',

        dataType: 'jsonp',

        timeout: 3500, 

        success: function (data) {

            $('#currentTemp').html(data.currently.temperature.toFixed(0));

            $('#minTemp').html(data.daily.data[0].temperatureMin.toFixed(0));

            $('#maxTemp').html(data.daily.data[0].temperatureMax.toFixed(0));

            $('#humidity').html(data.currently.humidity); 

            $('#windSpeed').html(data.daily.data[0].windSpeed.toFixed(0));

            $('#windBearing').html(data.daily.data[0].windBearing.toFixed(0));

            $('#visibility').html(data.daily.data[0].visibility.toFixed(0));

            $('#cloudCover').html(data.daily.data[0].cloudCover.toFixed(0));

            $('#pressure').html(data.daily.data[0].pressure.toFixed(0));

            $('#summary').html(data.currently.summary);

        }

    });
}

On default.aspx page replace the “PlaceHolderMain” control with the following code

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">

<label for="city">City: </label><label id="city"></label> <br />

    <label for="country-name">Country: </label><label id="country-name"></label>  <br />

    <label for="currentTemp">Current Temprature: </label><label id="currentTemp"></label> <br />

    <label for="minTemp">Min Temp: </label><label id="minTemp"></label> <br />

    <label for="maxTemp">Max Temp: </label><label id="maxTemp"></label> <br />

    <label for="humidity">Humidity (0-1): </label><label id="humidity"></label> <br />

    <label for="windSpeed">Wind Speed (km/h): </label><label id="windSpeed"></label> <br />

    <label for="windBearing">Wind Bearing: </label><label id="windBearing"></label> <br />

    <label for="Visibility">Visibility (km): </label><label id="visibility"></label> <br />

    <label for="cloudCover">Cloud Cover: </label><label id="cloudCover"></label> <br />

    <label for="pressure">Pressure (mb): </label><label id="pressure"></label> <br />

    <label for="summary">Summary: </label><label id="summary"></label> <br />

</asp:Content>

Press F5 and see the magic 

My Results

A user from London Office

 

You can build UI something like below using css once you have all the weather information in hand. 

    

Happy SharePoint coding Smile

AvatarByRashid Aziz

Missing user profile picture after updating mysite host URL in SharePoint 2013

Recently I had to change mysite host URL in one of our environment. After I update my site hots URL and ran full user profile sync. Everything was working fine until I noticed that user images are not appearing inside user profiles.

I have started looking into the issue and done the following steps to figure out the problem

I have checked the user profile “Picture” property to make sure that It is mapped to “PhotoThumbnail” property of active directory

Then I have checked that the Farm account have permissions on User profiles

Using the farm account I have ran the photo import command again 

Update-SPProfilePhotoStore –MySiteHostLocation http://mysiteHostUrl –CreateThumbnailsForImportedPhotos $true

With help of miisclient.exe I have confirmend that the picture property is pull the binary information from active directory. 

I then went to my profile and right click on the “PictureURL” and selected “Properties” option which open up the “Properties” popup window. Suddenly I realised that the URL of my user profile picture is still pointing to the old my site. 

 

I have copied the above picture URL in the browser, updated the “mysite” host URL to new one and hit enter. I was managed to see my profile picture as below.

 

At last I managed to find the issue. Now it’s time to fix it. So I wrote below PowerShell command to update all user profile picture properties URL.

$mySiteNewHostURL = "http://NewMySiteHostURL" 
$mySiteOldHostURL = "http://OldMySiteHostURL" 
$mySite = Get-SPSite $mySiteNewHostUrl 
$SPServiceContext = Get-SPServiceContext $mySite 

$userProfileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($SPServiceContext) 
$userProfiles = $userProfileManager.GetEnumerator() 
foreach ($userProfile in $userProfiles) 

{ 

  #check if the picture property contain image URL, then replace it with new my site host URL

  if ($userProfile["PictureURL"] -ne '') 

  { 
    $oldImageUrl = $userProfile["PictureURL"].toString() 
    $newImageUrl = $oldImageUrl -Replace $mySiteOldHostURL, $mySiteNewHostURL
    write-host "Old Image Link = " $oldImageUrl " --> New Image Link = " $newImageUrl 
    $userProfile["PictureURL"].Value = $newImageUrl 
    $userProfile.Commit() 

  }  
}

After I ran above PowerShell script, I was able to see  picture inside my user profile as below. Happy coding Smile

AvatarByRashid Aziz

Simple SharePoint hosted App “User Location Tracker”

You can follow the below steps to get user location information inside your SharePoint hosted app.

Create a “SharePoint Host App” project in visual studio 2013

Replace app.js contents with below code

jQuery.ajax({

    url: '//freegeoip.net/json/',

    type: 'POST',

    dataType: 'jsonp',

    success: function (location) {

        jQuery('#city').html(location.city);

        jQuery('#region-code').html(location.region_code);

        jQuery('#region-name').html(location.region_name);

        jQuery('#ip').html(location.ip);

        jQuery('#longitude').html(location.longitude);

        jQuery('#latitude').html(location.latitude);

        jQuery('#country-name').html(location.country_name);

        jQuery('#country-code').html(location.country_code);

    }

});

On default.aspx page replace the “PlaceHolderMain” control with the following code

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">

<label for="city">City: </label><label id="city"></label> <br />

<label for="country-name">Country: </label><label id="country-name"></label>  <br />

<label for="country-code">Country code: </label><label id="country-code"></label> <br />

<label for="region-name">Region: </label><label id="region-name"></label> <br />

<label for="region-code">Region code: </label><label id="region-code"></label> <br />

<label for="latitude">Latitude: </label><label id="latitude"></label> <br />

<label for="longitude">longitude: </label><label id="longitude"></label> <br />

<label for="ip">IP address: </label><label id="ip"></label> <br />

</asp:Content>

Press F5 and see the magic 

My Results

A user from London Office

 

 A user from Amsterdam office 

 

This is just the basic user location specific information I have managed to get using http://freegeoip.net free web service. Now you can use this information to drive user experience in you SharePoint environment. Good luck!

AvatarByRashid Aziz

Create Managed Property from Crawl Property in SharePoint 2013 Search via PowerShell

I have some custom properties in User Profile. I needed to create managed properties in SharePoint 2013 from custom user profile Crawl properties. I really don’t like doing things manually using SharePoint 2013 central administration site because then I have to recreate these properties on all different environments manually. So here is the script which will do the magic

User profile property name: City 

Crawl property display name: People:City

Crawl property full name: urn:schemas-microsoft-com:sharepoint:portal:profile:City 

You can get the crawl property full name from central admin UI

(Click on “search schema” link from search administration page 

Click “Crawled Properties” link

Search for your property, once it appear in result, click on it.

Crawl property detail page will open and will display the “Property Name” something like “urn:schemas-microsoft-com:sharepoint:portal:profile:City”) 

// Get the search service application

$searchapp = Get-SPEnterpriseSearchServiceApplication

// create base managed property 

$managedProperty_City= New-SPEnterpriseSearchMetadataManagedProperty -Name "City" -SearchApplication $searchapp -Type 1 -Queryable $true -Retrievable $true -FullTextQueriable $true

//Set “Refineable” and “Sortable” properties to true for this newly created managed property, by default these values will be set to false. You can skip this step if you don’t want to set the values to true

$managedProperty_City.Refinable=$true

$managedProperty_City.Sortable=$true

$managedProperty_City.Update()

//Get the crawl property which already exist and map it to the newly created managed property

$crawlProperty_City= Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -Limit 1 -Name "urn:schemas-microsoft-com:sharepoint:portal:profile:City"

New-SPEnterpriseSearchMetadataMapping -SearchApplication $searchapp -ManagedProperty $managedProperty_City -CrawledProperty $crawlProperty_City

Once you run these command, go to search schema page and search for the new managed property “City”. You should see the following result

 

Reference to get parameters detail: https://technet.microsoft.com/en-us/library/ff608089.aspx 

 

AvatarByRashid Aziz

Interactive JavaScript Maps Integration with SharePoint 2013 using Script Editor Web Part

I have a top level SharePoint site called “Our Offices” and sub site for each country office location (e.g. London, Berlin etc.). The “Our Offices” site home page needs to provide easy navigation to all offices sub sites. Also, I wanted to show where this office location reside on the world map and when someone click on the location, system should redirect the user to that location site home page. 

To do this I have used AmMap solution. The JavaScript / HTML5 mapping library (jsmap) help to create interactive, animated maps and display them in your web sites or web applications.

Navigate to http://www.amcharts.com/javascript-maps/ and click on download button.  

 On the next page, click “Interactive JavaScript Maps” download link as highlighted below.

 Once downloaded, extract the zip folder and give the root folder a proper name.  (By default it will be something like “ammap_3.13.1.free”. I have renamed the root folder to “CoolMaps”)

Copy the “CoolMaps” folder, Navigate to SharePoint 15 hive Layouts folder (C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS) and past the “CoolMaps” folder here.

Add “Script Editor” web part on “Our Offices” site home page.

 

 Copy and paste the following code into your script editor web part.

Note: Please updated the locations and SharePoint sub site URLs as per your business requirements.

<link rel="stylesheet" href="/_layouts/15/CoolMaps/ammap/ammap.css" type="text/css">
        <script src="/_layouts/15/CoolMaps/ammap/ammap.js" type="text/javascript"></script>
        <!-- map file should be included after ammap.js -->
	<script src="/_layouts/15/CoolMaps/ammap/maps/js/worldLow.js" type="text/javascript"></script>

		<script type="text/javascript">
			var map;

			// svg path for target icon
			var targetSVG = "M9,0C4.029,0,0,4.029,0,9s4.029,9,9,9s9-4.029,9-9S13.971,0,9,0z M9,15.93 c-3.83,0-6.93-3.1-6.93-6.93S5.17,2.07,9,2.07s6.93,3.1,6.93,6.93S12.83,15.93,9,15.93 M12.5,9c0,1.933-1.567,3.5-3.5,3.5S5.5,10.933,5.5,9S7.067,5.5,9,5.5 S12.5,7.067,12.5,9z";

			AmCharts.ready(function() {
			    map = new AmCharts.AmMap();
			    map.pathToImages = "/_layouts/15/CoolMaps/ammap/images/";

			    map.imagesSettings = {
			        rollOverColor: "#FFA02F",
			        rollOverScale: 3,
			        selectedScale: 3,
			        selectedColor: "#FE5815",
                                color: "#FE5815"
			    };

			    var dataProvider = {
			        mapVar: AmCharts.maps.worldLow,
			        images: [
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"London", latitude:51.5002, longitude:-0.1262, url: "../London"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Paris", latitude:48.8567, longitude:2.3510, url: "../Paris"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Berlin", latitude:52.5235, longitude:13.4115, url: "../Berlin"},	
{svgPath:targetSVG, zoomLevel:5, scale:0.5, title:"Amsterdam", latitude:52.3738, longitude:4.8910,  url: "../Amsterdam"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Singapore", latitude:1.2894, longitude:103.8500, url: "../Singapore"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Islamabad", latitude:33.6751, longitude:73.0946, url: "../Islamabad"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Beijing", latitude:39.904030, longitude:116.40752599, url: "../Beijing"},	
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Tokyo", latitude:35.6785, longitude:139.6823,  url: "../Tokyo"},				   
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Chicago", latitude:41.87811360, longitude:-87.6297981999, url: "../Chicago"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Bucharest", latitude:44.4479, longitude:26.0979, url: "../Bucharest"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"Moscow", latitude:55.7558, longitude:37.6176, url: "../Moscow"},
{svgPath:targetSVG, zoomLevel:5, scale:1.0, title:"San Marino", latitude:43.9424, longitude:12.4578, url: "../SanMarino"}
			        ]
			    };
			    map.dataProvider = dataProvider;

			    map.objectList = new AmCharts.ObjectList("listdiv");
			    map.showImagesInList = true;

			    map.write("mapdiv");

			});

        </script>
    <div>
        <div id="listdiv" style="width:200px; overflow:auto; height:500px; float:right; background-color:#FFFFFF;"></div>
        <div id="mapdiv" style="margin-right:200px; background-color:#FFFFFF; height: 500px;"></div>
    </div>
<br/>

 

Save the page and publish it. 

The Map should appear like this on the page

 

On mouse hover it will highlight the location on the map and when user click on a location, it will take you to pre-configured sub site for that location. 

The map I am showing here is just for demo purpose. There are many more types of maps available in this library. Go and explore the rest Smile

AvatarByRashid Aziz

Angular JS and Bootstrap to Display SharePoint 2013 List Data using Script Editor

I am big fan of using OOTB stuff, but sometime customer want to see things in different way or their organisational design guidelines are difficult to achieve using OOTB functionality.

In my previous post I have explained how to customise SharePoint list form using Angular JS and Bootstrap 

Here, I will show you how to display list items using bootstrap and AngularJS.  I have picked a scenario: I have SharePoint 2013 list called “Customer Details”. The list have following columns

Schema name

Display name

Title

Customer name

City

City

Country

Country

ContactPerson

Contact person

 

The list default OOTB view appear as below

The customer want to display this list data on a page but with complex UI design. OOTB list web part will only display the data in same way as it appears in the list view.

One way to achieve the complex design is by using AngularJS and Bootstrap.

1.  Create a new page inside SharePoint 2013 site “Pages” library.

 2.  Add a “Script Editor” web part on the page

3.  Copy and paste the following code inside script editor web part

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>  
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
 
<script>
    var angApp = angular.module('SharePointAngApp', []);
    angApp.controller('spCustomerController', function ($scope, $http) {
        $http({
            method: 'GET',
            url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('Customer Details')/items?$select=Title,City,Country,ContactPerson",
            headers: { "Accept": "application/json;odata=verbose" }
        }).success(function (customerData, status, headers, config) {
            $scope.customers = customerData.d.results;
        }).error(function (customerData, status, headers, config) {
      
        });
    });
   
</script>
    <link data-require="bootstrap-css@*" data-semver="3.0.0" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
	 <div ng-app="SharePointAngApp">
	 <div ng-controller="spCustomerController">
	 <br/>
        <table class="table table-striped table-hover">
            <tr>
                <th>Customer name</th>
                <th>City</th>
                <th>Country</th>
				 <th>Contact person</th>
              
            </tr>
            <tr ng-repeat="customer in customers">
                <td>{{customer.Title}}</td>
                <td>{{customer.City}}</td>
                <td>{{customer.Country}}</td>
				<td>{{customer.ContactPerson}}</td>
                </tr>
        </table>
    </div>
	</div>


Now, the list data will appear as below inside script editor web part.

AvatarByRashid Aziz

SharePoint 2013 Custom List Form using Angular JS and Bootstrap

According to  Microsoft InfoPath Forms Services for SharePoint Server 2013 will be supported until April 2023. Keeping that in mind I have started looking into alternatives to build rich form which can be used with SharePoint list and replace OOTB form. I have started looking into Angular JS (AngularJS is a JavaScript framework. AngularJS extends HTML attributes with directives and binds data to HTML with expressions). From user interface point of view I spend some time with bootstrap (Bootstrap makes front-end web development faster and easier).

In the below example, I will use both AngularJS and Bootstrap to build custom SharePoint 2013 form to create new list items.

For this demo purpose, I will use SharePoint page with “Script Editor” to build this form. I highly recommend to use visual studio to build .aspx and .js files and update list schema to change lists default New/Edit forms.

1.Create “Customer Details” list which have the following column

Schema name

Display name

Title

First name

LastName

Last name

Address

Address

 

2.     Now create a new page in SharePoint 2013 “Pages” library. 

 

3.     Add “Script Editor” web part on the page.

 

4.     Copy and paste the following code inside script editor

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>  
<script>  
    function mainController($scope) {  
  
        $scope.customer = { firstName: "", lastName: "", location: "" };  
        $scope.createContact = function ($event) {  
            var c = $scope.customer;  
            $event.preventDefault();  
  
            var clientContext = new SP.ClientContext.get_current();  
            var web = clientContext.get_web();  
            var list = web.get_lists().getByTitle('Customer Details');  
            var customerListItemInfo = new SP.ListItemCreationInformation();  
            var listItem = list.addItem(customerListItemInfo);  
            listItem.set_item('Title', c.firstName);  
            listItem.set_item('LastName', c.lastName);
             listItem.set_item('Address', c.address); 			 
            listItem.update();  
            clientContext.executeQueryAsync(  
                Function.createDelegate(this, onQuerySucceeded),  
                Function.createDelegate(this, onQueryFailed)  
            );  
  
        };  
  
        onQuerySucceeded = function () {  
            alert('Successfully created new customer record');  
        }  
  
        onQueryFailed = function (sender, args) {  
            alert('Failed: ' + args.get_stackTrace());  
        }  
    }  
</script>  
  
<h2>Customer Information:</h2>  
<br />  
<div ng-app="">  
    <div ng-controller="mainController">  
        First name  
        <input type="text" ng-model="customer.firstName" /><br />  
        <br />  
        Last name
        <input type="text" ng-model="customer.lastName" /><br />  
        <br />  
        Address
		<input type="text" ng-model="customer.address" /><br />  
        <br />  
        <input type="submit" value="Save" ng-click="createContact($event)" />  
    </div>  
</div>

 

5.     Save the page and publish it. The form will look something like this.

You can now go ahead and start using the form to create new customer records, but I like to make the user interface a little better.

To do that, I have added bootstrap css library reference and added some classes with html elements.

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>  
<script>  
    function mainController($scope) {  
  
        $scope.customer = { firstName: "", lastName: "", location: "" };  
        $scope.createContact = function ($event) {  
            var c = $scope.customer;  
            $event.preventDefault();  
  
            var clientContext = new SP.ClientContext.get_current();  
            var web = clientContext.get_web();  
            var list = web.get_lists().getByTitle('Customer Details');  
            var customerListItemInfo = new SP.ListItemCreationInformation();  
            var listItem = list.addItem(customerListItemInfo);  
            listItem.set_item('Title', c.firstName);  
            listItem.set_item('LastName', c.lastName);
             listItem.set_item('Address', c.address); 			 
            listItem.update();  
            clientContext.executeQueryAsync(  
                Function.createDelegate(this, onQuerySucceeded),  
                Function.createDelegate(this, onQueryFailed)  
            );  
  
        };  
  
        onQuerySucceeded = function () {  
            alert('Successfully created new customer record');  
        }  
  
        onQueryFailed = function (sender, args) {  
            alert('Failed: ' + args.get_stackTrace());  
        }  
    }  
</script>  
      <link data-require="bootstrap-css@*" data-semver="3.0.0" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
<h2>Customer Information:</h2>  
<br />  
<div ng-app="">  
    <div ng-controller="mainController" class="col-xs-5 selectContainer form-group">  
        First name  
        <input type="text" ng-model="customer.firstName" class="form-control"/><br />  
        <br />  
        Last name
        <input type="text" ng-model="customer.lastName" class="form-control" /><br />  
        <br />  
        Address
		<input type="text" ng-model="customer.address" class="form-control" /><br />  
        <br />  
        <input type="submit" value="Save" ng-click="createContact($event)" class="btn btn-primary btn-lg active" />  
    </div>  
</div>

You can see the difference as it look more professional after adding couple of bootstrap css classes.

 

I hope the above demonstration is helpful. Smile