Monday, April 17, 2017

How to create a SharePoint page to support Tab navigation within the Web Part page with JQuery Tabs Widget?

It is a very easy to have a tabs sections enable in the page with Jquery tab widget. if we need to implement a  tab navigation in the web part page, we can use the JQuery tab widget to accomodate this approach.

It is better to use a pay layout template to customize the web part page, we can use this template to properly put each webpart into different web part zone. we then can use this page layout template to create the new page.

We can use the following step to complete this task.

1. go to Master Page Library by selecting the site setting from Settings icon on the top right corn.





2. click on the Master Page And The Page Layout to access the Master Page Library


3. download a copy of welcomePageLayout.aspx


 4. Rename the Welcome Layout Page to TabPage.aspx

5. Open the TabPage.aspx with Visual Studio Code. and paste the following code after the Library Registration Section. Which will add javascript file reference and enable Tab in the Document.ready event.


<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">
   
<SharePoint:CssRegistration name="<% $SPUrl:~sitecollection/Style Library/~language/Themable/Core Styles/pagelayouts15.css %>" runat="server"/>
<!-- Reference the jQueryUI theme's stylesheet on the Google CDN. Here we're using the "Start" theme -->
    <link  type="text/css" rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/start/jquery-ui.css" />
    <!-- Reference jQuery on the Google CDN -->
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <!-- Reference jQueryUI on the Google CDN -->
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
    <style type="text/css">
        .ms-bodyareaframe
        {
            padding: 0px;
        }

        #tabs {
                    background: none;
                    border: none;
                }
                #tabs .ui-widget-header {
                    height: 40px;
                    background: none;
                    border: none;
                    -moz-border-radius: 0px;
                    -webkit-border-radius: 0px;
                    border-radius: 0px;
                }
    </style>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#tabs").tabs();

        });
    </script>
    <PublishingWebControls:EditModePanel runat="server">
        <!-- Styles for edit mode only-->
        <SharePoint:CssRegistration name="<% $SPUrl:~sitecollection/Style Library/~language/Themable/Core Styles/editmode15.css %>"
            After="<% $SPUrl:~sitecollection/Style Library/~language/Themable/Core Styles/pagelayouts15.css %>" runat="server"/>
    </PublishingWebControls:EditModePanel>
</asp:Content>

6.  put this snippet of code in the Main PlaceHolder to get the Web Part Zone Layout Configuration in place.

<asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server">
    <div class="">
        <!--<PublishingWebControls:EditModePanel runat="server" CssClass="edit-mode-panel title-edit">
            <SharePoint:TextField runat="server" FieldName="Title"/>
        </PublishingWebControls:EditModePanel>    -->
            <div id="tabs">
            <ul>
                <li><a href="#Sales-Dasboard">Sales Dasboard</a></li>
                <li><a href="#Sales-Report">Sales Report</a></li>
            </ul>
            <div id="Sales-Dasboard">
            <div class="ms-table ms-fullWidth">
            <div class="tableCol-100">
                <div class="cell-margin">
                    <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_Header%>" ID="Header"/>
                </div>
                <div class="ms-table ms-fullWidth">
                    <div class="cell-margin" style="width:49.9%;display: table-cell;">
                        <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_CenterLeft%>" ID="CenterLeftColumn1" />
                    </div>
                    <div class="cell-margin" style="width:1%;display: table-cell;">
                        &nbsp;
                    </div>
                    <div class="cell-margin" style="width:48.9%;display: table-cell;">
                        <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_CenterRight%>" ID="CenterRightColumn1" />
                    </div>
                </div>
                <div class="cell-margin">
                    <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_Center%>" ID="Middle1"/>
                </div>
                <div class="cell-margin">
                    <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_Center%>" ID="Middle2"/>
                </div>
                <div class="ms-table ms-fullWidth">
                    <div class="cell-margin" style="width:49.9%;display: table-cell;">
                        <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_CenterLeft%>" ID="CenterLeftColumn2" />
                    </div>
                    <div class="cell-margin" style="width:1%;display: table-cell;">
                        &nbsp;
                    </div>
                    <div class="cell-margin" style="width:48.9%;display: table-cell;">
                        <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_CenterRight%>" ID="CenterRightColumn2" />
                    </div>
                </div>
                <div class="cell-margin">
                    <WebPartPages:WebPartZone runat="server" Title="<%$Resources:cms,WebPartZoneTitle_Footer%>" ID="Footer"/>
                </div>
            </div>
            <SharePoint:ScriptBlock runat="server">if(typeof(MSOLayout_MakeInvisibleIfEmpty) == "function") {MSOLayout_MakeInvisibleIfEmpty();}</SharePoint:ScriptBlock>
        </div>
            </div>
            <div id="Sales-Report">
                <WebPartPages:WebPartZone runat="server" Title="loc:CaseStudies" ID="CaseStudies" FrameType="TitleBarOnly"><ZoneTemplate>
                </ZoneTemplate></WebPartPages:WebPartZone>
            </div>
            </div>
    </div>
</asp:Content>

7. Upload the tabPage.aspx to the Master Page Library.
  •      Selected Page Layout from Content Type section dropdown list
  •      Selected Page Layout Content Type from Content Type Group Dropdown list
  •      Select Welcome Page from Content Type Name dropdown List.



8. Go to Page library and Create a new page by Selecting
TabPage.aspx  from the list box under Page Layout section.




9. when you click your newly created page. you will see your tab like this

Tab One Web Part Zone Layout



Tab Two Web Part Zone Layout

Tuesday, April 11, 2017

Advanced configuration and implementation in enabling Cross-Origin Requests in ASP.NET Web API 2

After we deploy the Web Api or WCF to cloud or in the public network. It means that we already expose the data to any one who know the url of the Web Api or WCF.

I will skip the introduction to setting up the Cross-Origin Requests in ASP.NET Web API 2 here.

For more information about the CORS for Web Api. you can visit MSDN link

Enabling Cross-Origin Requests in ASP.NET Web API 2


i will only focus on the a little bit advance topic on CORS implementation, since i had spend
extend period of time to complete the implementation.


1. control the CORS with custom setting in web.config file.

the configuration setting will allow us to add more domains without any code change and depolyment, we only need system admin to add more domain in the name attribute that separate by
comma.

<configSections>
    <section name="CORSSettings" type="MyApp.CORSSettings, MyApp" />
  </configSections>


 <CORSSettings>
    <CorsSupport>
      <Domain Name="http://firstdomain,http://seconddomain,http://thirddomain" AllowMethods="*" AllowHeaders="*" AllowCredentials="true">
      </Domain>
    </CorsSupport>
  </CORSSettings>


2. Server Side Implementation  

 In the WebApiConfig class

added the following code to enable the CORS globally

var cORSSettings = ConfigurationManager.GetSection("CORSSettings") as CORSSettings;
            if (cORSSettings == null)
                throw new InvalidOperationException("Missing CORS configuration");
            var domains = cORSSettings.CorsSupport.OfType<CorsDomain>();
            foreach (var domain in domains)
            {
                var cors = new EnableCorsAttribute(domain.Name, domain.AllowHeaders, domain.AllowMethods);
                cors.SupportsCredentials = true;
                config.EnableCors(cors);
            }

please ensure the CORS object with property SupportsCredentials to be True, if your web api is configured with windows authentication and disable anonymous access. otherwise you will always receive XMLHttpRequest Network Error




3. Client Side Implementation

Even though you have enable the cors with SupportCredentials, you still will encouter the PreFlight request OPTIONS Error like
  "Origin http://YourDomain is not allowed by Access-Control-Allow-Origin"

when you use .ajax the jquery wrappper to execute the client call

$.ajax({
    type: 'get',
    url: 'http://www.example.com/api/test',
    xhrFields: {
        withCredentials: true
    }

actually we should use this XMLHttpRequest directly to call the web api to solve the preFlight request OPTIONS Error


                    var xmlHttpRequest = new XMLHttpRequest();
                    xmlHttpRequest.open('GET', sWCFUrl, true);
                    xmlHttpRequest.withCredentials = true;
                    xmlHttpRequest.onreadystatechange = processData;
                    xmlHttpRequest.send();
     

 I hope this post can help solve the headache on CORS implementation especiallly with windows authentication eanble and anonymous access diable.







How to use JSOM to get the list of documents from SharePoint Document Library

there are so many way to perform a task that iterating the list of document inside the docoumnt library. we can do either with CSOM with C# or JSOM with Javascript.

Here i will show a very simple way to execute this task.

<script type="text/javascript">
function getDocuments(title) {
   var context = SP.ClientContext.get_current();
   var web = context.get_web();
   var docLibrary = web.get_lists().getByTitle();
//here we can use SP.CamlQuery to filter the list if we need to
//load the the document by certain criteria.
   var items = docLibrary.getItems(SP.CamlQuery.createAllItemsQuery());
   context.load(items,"Include(File)");
   context.executeQueryAsync(
     function () {
        if (items.get_count() > 0) {
            var e = items.getEnumerator();
            while (e.moveNext()) {
                var item = e.get_current();
                var file = item.get_file();
                var title = file.get_title();
                var name = file.get_name();
                console.log(title + "      " + name );
            }
        }
     },
     function (sender, args) {
        console.log("Error in Loading Documents: " + args.get_message());
     }
     );
}



// We will use the delegate function to allow the ExecuteOrDelayUntilScriptLoaded function
//run a function with paramenters and this fucntion will ensure that sp.js is sucessfully loaded
//before running getDocuments function.

$(document).ready(function () {
   ExecuteOrDelayUntilScriptLoaded(function() {getDocuments("Sales Documents")}, "sp.js");
});
</script>


For more information please visit the following link from MSDN

How to: Retrieve List Items Using JavaScript

Friday, March 31, 2017

How to configure a WCF service running like Rest Service?

I have various posts on the configure of WCF. i will show you another configure if you want your WCF service to call with rest service call like

http://WCFHostServer/myWCF.svc/YourMethod

Note to be taken:

1. must use the webHttpBinding.
2. enable HttpsGet in service behaviors setting
3. add <webHttp> to endpoint behavior setting.

here is WCF configuration in my sample wcf application

  <system.serviceModel>
    <services>
      <service name="MyWCF"
               behaviorConfiguration="MyWCF.Service1Behavior">
        <endpoint address="" binding="webHttpBinding" behaviorConfiguration="EndPointBehavior"
                  contract="MyWCF.IMyWCF"
                    bindingConfiguration="wbBind">
          </endpoint>
          </service>
        </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyWCF.Service1Behavior">
          <serviceMetadata httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <serviceCredentials>
            <windowsAuthentication allowAnonymousLogons="False" includeWindowsGroups="True"/>
          </serviceCredentials>
          </behavior>
        </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="EndPointBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <webHttpBinding>
        <binding name="wbBind">
          <security mode="Transport">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows"/>
            </security>
            </binding>
          </webHttpBinding>
    </bindings>
  </system.serviceModel>

How to add an event handle to dynamic generated HTML content?

when we have a static web content, we can add an javascript function to the element on Doccument.ready Event.

<table><tr id="myRow"><td></td></tr><table>

in  $(document).ready(function () {
    $("myRow").onClick(function(event){
        var $this = $(this);
        var tbody= $(this).closest('tbody').next('tbody');
        if (tbody.hasClass("collapsed")) {
            var img=$this.find('.expandImg');
            $this.find('.expandImg').attr("src","/_layouts/images/minus.gif");
            tbody.removeClass("collapsed");
        } else {
            tbody.addClass("collapsed");
            $this.find('.expandImg').attr("src","/_layouts/images/plus.gif");
        }
}

However, if the html content is created in the fly. then click event no longer work,
we should use the .live() instead of onClick
$(".myRow").live('click', function(event){
        var $this = $(this);
        var tbody= $(this).closest('tbody').next('tbody');
        if (tbody.hasClass("collapsed")) {
            var img=$this.find('.expandImg');
            $this.find('.expandImg').attr("src","/_layouts/images/minus.gif");
            tbody.removeClass("collapsed");
        } else {
            tbody.addClass("collapsed");
            $this.find('.expandImg').attr("src","/_layouts/images/plus.gif");
        }