<script> </script>和 <script text templateype="text/javascript

HTML &pre& 标签Alex Choroshin |
You may also be interested in:
Editor’s note: Contributor Alex Choroshin is a Sharepoint Team Leader at . Follow him
Working with REST API is quite simple and straight forward. For example when you need to fetch data from a list you can use the following JQuery Ajax code snippet:
jQuery.ajax({
url: &http://YourSite/_api/web/lists/getbytitle('ListName')/items&,
type: &GET&,
headers: { &Accept&: &application/odata=verbose& },
success: function(data, textStatus, xhr) {
var dataResults = data.d.
alert(dataResults[0].Title);
error: function(xhr, textStatus, errorThrown) {
alert(&error:&+JSON.stringify(xhr));
Another good example is when you need to get specific fields like “Title”, “ID” or “Modified” , you can use the &$select keyword.
For example:
url: &http://YourSite/_api/web/lists/getbytitle('ListName')/items$select= Title ,ID, Modified&,
type: &GET&,
headers: { &Accept&: &application/odata=verbose& },
success: function(data, textStatus, xhr) {
var dataResults = data.d.
alert(dataResults[0].Modified);
error: function(xhr, textStatus, errorThrown) {
alert(&error:&+JSON.stringify(xhr));
But what happens when you need to get a user/group field like “Author” ? well, things are not as obvious as they seem.
Unfortunately you can’t use /getbytitle(‘ListName’)/items or /getbytitle(‘ListName’)/items?filter=Author to get the user field since this field does not exist in the response data, but luckily for us we have an “AuthorId” field that (as you already guessed) will get us the user id.
So, after getting the user id from your list you need to make another Ajax call to get the user login name/display name by using /_api/Web/GetUserById method .
function getUser(id){
var returnV
jQuery.ajax({
url: &http://YourSite/_api/Web/GetUserById(& + id + &)&,
type: &GET&,
headers: { &Accept&: &application/odata=verbose& },
success: function(data) {
var dataResults = data.d;
//get login name
var loginName
= dataResults.LoginName.split('|')[1];
alert(loginName);
//get display name
alert(dataResults.Title);
Full Example:
jQuery.ajax({
url: &/SiteName/_api/web/lists/getbytitle('ListName')/items&,
type: &GET&,
headers: { &Accept&: &application/odata=verbose& },
success: function(data, textStatus, xhr) {
var dataResults = data.d.
var resultId = dataResults[0].AuthorId.results[0];
getUser(resultId)
error: function(xhr, textStatus, errorThrown) {
alert(&error:&+JSON.stringify(xhr));
function getUser(id){
var returnV
jQuery.ajax({
url: &http://YourSite/_api/Web/GetUserById(& + id + &)&,
type: &GET&,
headers: { &Accept&: &application/odata=verbose& },
success: function(data) {
var dataResults = data.d;
//get login name
var loginName
= dataResults.LoginName.split('|')[1];
alert(loginName);
//get display name
alert(dataResults.Title);
I would like to thank Ofir Elmishali for helping me with this post.
Hope you’ll find this post helpful.
You may also be interested in:
Editor’s note: Contributor Alex Choroshin is a Sharepoint Team Leader at . Follow him
The problem is caused by the fact that IIS supports specifying multiple IIS bindings per site (which results in multiple base addresses per scheme, in our case HTTP), but a WCF service hosted under a site allows binding to only one base address per scheme.
Multiple addresses example (in our case two):
Create a custom service factory to intercept and remove the additional unwanted base addresses that IIS was providing.
A) Add the custom service factory to your Custom.svc file
&%@ServiceHost language=c# Debug=&true& Service=&MySolution.Services.CustomService, $SharePoint.Project.AssemblyFullName$&
Factory=&MySolution.Core.CustomHostFactory&, $SharePoint.Project.AssemblyFullName$ %&
* Don’t forget to add the assembly full name: $SharePoint.Project.AssemblyFullName$ or you’ll get “The CLR Type ‘typeName’ could not be loaded during service compilation” error.
B) Create a custom factory by inheriting from ServiceHostFactory and overriding the CreateServiceHost method.
By using the current request host name you can check which base address to use, and if no host name found, use the first one.
public class CustomServiceHostFactory : ServiceHostFactory
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
string hostName = HttpContext.Current.Request.Url.H
foreach (Uri uri in baseAddresses)
if (uri.Host == hostName)
return new ServiceHost(serviceType, uri);
return new ServiceHost(serviceType, baseAddresses[0]);
public class CustomHost : ServiceHost
public CustomHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
protected override void ApplyConfiguration()
base.ApplyConfiguration();
Hope you’ll find this post helpful.
You may also be interested in:
Editor’s note: Contributor Alex Choroshin is a Sharepoint Team Leader at . Follow him
The onet.xml file is basically divided into two parts, first is the &SiteFeatures& element and the second element is called &WebFeatures&. The &SiteFeatures& Section that holds the site features starts activating all the features only when creating a site collection. The &WebFeatures& Section that holds the web features starts activating all the web scoped features only when creating a site.
Scenario: you created a custom web template and deployed the solution but when trying to create a site from your custom web template you get the following error &the site template requires that the feature {GUID} be activated in the site collection&. Of course you can always activate the site collection scoped feature manually but, let’ you need all the necessary features to be automatically activated.
Solution: When creating a site you need to trigger the site collection scoped feature using a web scoped feature.
The steps are:
A) Create an empty web scoped feature and in the &FeatureActivated& Event Receiver add the following code:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
//Ensure that scope is correctly set
if (properties.Feature.Parent is SPWeb)
SPWeb web = (SPWeb)properties.Feature.P
foreach (SPFeatureProperty property in properties.Feature.Properties)
Guid featureGuid = new Guid(property.Value);
//Verify feature status
SPFeature feature = web.Site.Features[featureGuid];
if (feature == null)
//Activate site collection scoped feature, if requested and not currently activated
web.Site.Features.Add(featureGuid);
catch (Exception ex)
B) In the onet.xml file in the &WebFeature& Element, add the following xml:
&WebFeatures&
&!-- Custom Site collection scoped feature activation --&
&Feature ID=&YourEmptyFeatureGuid&&
&Properties xmlns=&/sharepoint/&&
&Property Key=&SiteScopedGUID& Value=&YourSiteCollectionFeatureID&/&
&/Properties&
&/Feature&
&/WebFeatures&
In the Feature ID element add your empty feature’s ID
In the Property Key=&SiteScopedGUID& element add the site collection feature id that you want to activate.
Hope you’ll find this post helpful
You may also be interested in:
Editor’s note: Contributor Alex Choroshin is a Sharepoint Team Leader at . Follow him
When you want to bind an event handler to the &keypress& JavaScript event, or trigger that event on an element, you can achieve this using a JQuery handler like .
For example, binding &keypress& event to a text box on your custom control:
$(&#input&).keypress(function (event) {
var code = (event.keyCode ? event.keyCode : event.which);
if(code == 13) //Enter keycode
// your logic here...
As you can see, the task is very simple and straightforward, but when dealing with SharePoint, sometimes things get pretty messy.
Scenario: You developed a custom control with a text box and used a &keypress& JavaScript event to trigger the “Enter” key press event . You added the control to a SharePoint page and it worked, but after adding a SharePoint OOTB control that also has a text box, your &keypress& event automatically stops working. Why you ask? Well, it’s all about priorities. If your JS code is last in order, then your code would probably work, but you can never be sure.
Solution: Use the
method to stop the default action of the event, in our case, SharePoint OOTB controls.
$(&#input&).keypress(function (event) {
var code = (event.keyCode ? event.keyCode : event.which);
if(code == 13) //Enter keycode
//stop the default action of the Enter key
event.preventDefault();
// your logic here...
This way, we gained control over our events and managed to keep the OOTB functionality working.
Hope you find this article handy .
You may also be interested in:
Editor’s note: Contributor Alex Choroshin is a Sharepoint Team Leader at . Follow him
The Development Stage
In my last post
we discussed the reason I chose Windows 8 HTML5 as my development environment and why it’s the best and the most intuitive environment for SharePoint developers who plan to start creating Win8 apps.
Today we will focus on developing our Win8 app and integrate it with SharePoint Online 2013. The app will serve as a search and use
to pull data from SharePoint 2013 Search engine () and display it in our app.
When I decided to connect my Win8 app to SharePoint 2013 Online, it seemed like a straightforward task. All I wanted is to programmatically connect to SharePoint Online services but reality shows otherwise. I thought the answer could be found in one of ’s capabilities integrating with . after exploring this API for several days and even posting a question on Windows Store apps Forums asking “” which, unfortunately for me, still haven’t got any answer to. then I decided it’s time to take matters in hand and develop my own custom connector to SharePoint Online services.
Before starting to develop any solution, it’s important to understand how SharePoint Online authentication works. The authentication &mechanism& is called . First we request the token from the STS, we pass the username and password. then the STS returns a security token. After we get our security token we send it to SharePoint and at last we get our two cookies called “FedAuth” and “rtFa” that we need to pass every time we want to request something from SharePoint.
Luckily for me I found
great article by
explaining how to do active authentication to Office 365 and SharePoint Online using WCF. Since the code sample provided was targeting framework 3.5, I tweaked it a little bit to work with framework 4.5, called it Office365ClaimsConnector and it worked like a charm.
So let’s get to work
Step 1: creating a blank application
Start VS2012 & Other Languages &JavaScript & Blank App. Name it “Win8AppForSharePoint”
Step 2: creating the Windows Storage & Navigation for our pages
WinRT has a great
and we have access to the following types:
a) local – data but only on the current device
b) roaming – data that is available to all devices the user has your app installed on
c) temporary – data that can be removed by the system at any point after your app is closed
Since our app will only be installed on one device we’ll steak with the local Storage.
Open the “default.html” and add : &div id=&contentHost&&&/div& we’ll use this div later for navigation purposes.
Open the “default.js” file and add the following JavaScript code.
// For an introduction to the Blank template, see the following documentation:
// /fwlink/?LinkId=232509
(function () {
&use strict&;
var app = WinJS.A
var activation = Windows.ApplicationModel.A
var localSettings = Windows.Storage.ApplicationData.current.localS
var containerName = &cookieContainer1&;
WinJS.strictProcessing();
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
args.setPromise(WinJS.UI.processAll().then(function () {
if (isAuthenticated())
return WinJS.Navigation.navigate(&/pages/Search/search.html&);
return WinJS.Navigation.navigate(&/pages/Login/login.html&);
WinJS.Navigation.addEventListener(&navigated&, function (eventObject) {
var url = eventObject.detail.
var host = document.getElementById(&contentHost&);
WinJS.Utilities.empty(host);
eventObject.detail.setPromise(WinJS.UI.Pages.render(url, host, eventObject.detail.state).then(function () {
WinJS.Application.sessionState.lastUrl =
function isAuthenticated() {
if (localSettings.containers.hasKey(containerName)) {
app.start();
In the isAuthenticated function we’re using the Windows.Storage.ApplicationData object to check if our data (user name, password, url) is already stored and navigate to the appropriate page. If Authenticated, navigate straight to Search page, or else go through the login page.
Step 3: Creating WCF Service
Create a WCF Service Application Project, Name it “Office365ClaimsService”.
Create 2 classes, first a static class called DAL, and a second class called QueryStringHelper. We’ll use this class later for query formatting.
Open Ioffice365ClaimsService.cs and add the following code .
using System.Collections.G
using System.L
using System.Runtime.S
using System.ServiceM
using System.ServiceModel.W
using System.T
namespace Office365ClaimsService
// NOTE: You can use the &Rename& command on the &Refactor& menu to change the interface name &IService1& in both code and config file together.
[ServiceContract]
public interface IOffice365ClaimsService
[OperationContract]
[WebInvoke(Method = &POST&, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = &/authentication&)]
TokenContainer Authentication(string url, string userName, string password);
[OperationContract]
[WebInvoke(Method = &POST&, ResponseFormat = WebMessageFormat.Json, RequestFormat=WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = &/search&)]
string GetSearchData(string FedAuth, string RtFa, string url, string query);
[DataContract]
public class TokenContainer
[DataMember]
public string
FedAuth { }
[DataMember]
public string RtFa { }
We’ll have 2 Services, First is an Authentication service that receives the following parameters : url, userName, password. The second service is the search service receiving the following parameters : FedAuth, RtFa, url, query
Since we’re working with JavaScript and handle some sensitive data, the 2 Service’s use JSON as the Request Format & Response format and the type method is POST.
Open the DAL.cs file and add the following code.
using System.Collections.G
using System.IO;
using System.L
using System.N
using System.Threading.T
using System.W
using Office365ClaimsC
namespace Office365ClaimsService
public static class DAL
public static TokenContainer getTokens(string url, string userName, string password)
TokenContainer tc = new TokenContainer();
MsOnlineClaimsHelper claimsHelper = new MsOnlineClaimsHelper(url, userName,password);
CookieContainer cc=claimsHelper.GetCookieContainer();
tc.FedAuth = cc.GetCookies(new Uri(url))[&FedAuth&].V
tc.RtFa = cc.GetCookies(new Uri(url))[&rtFa&].V
public static string GetDataFromSP(string FedAuth,string RtFa, string url, QueryType type, string query)
string responseJson = string.E
var uri = QueryStringHelper.BuildQuery(QueryType.Search, url, query);
CookieContainer cc = GetCookieContainer(FedAuth, RtFa, new Uri(url));
Uri queryUri = new Uri(uri.AbsolutePath);
var request = HttpWebRequest.CreateHttp(uri);
request.Method = &GET&;
var accept = &application/json&;
if (accept != null)
request.Accept =
request.CookieContainer=
var response = request.GetResponse();
Stream res = response.GetResponseStream();
using (var reader = new StreamReader(res))
responseJson = reader.ReadToEnd();
return responseJ
private static CookieContainer GetCookieContainer(string FedAuth, string rtFa, Uri uri)
CookieContainer _cachedCookieContainer =
DateTime _expires = DateTime.MinV
CookieContainer cc = new CookieContainer();
if (_cachedCookieContainer == null || DateTime.Now & _expires)
// Set the FedAuth cookie
Cookie samlAuth = new Cookie(&FedAuth&, FedAuth)
Expires = _expires,
Path = &/&,
Secure = uri.Scheme == &https&,
HttpOnly = true,
Domain = uri.Host
cc.Add(samlAuth);
// Set the rtFA (sign-out) cookie, added march 2011
Cookie rtFaCookie = new Cookie(&rtFA&, rtFa)
Expires = _expires,
Path = &/&,
Secure = uri.Scheme == &https&,
HttpOnly = true,
Domain = uri.Host
cc.Add(rtFaCookie);
_cachedCookieContainer =
You’ll need to add a reference to Office365ClaimsConnector project. As a reminder, Office365ClaimsConnector is the code sample I found in
great article by
that actually does all the Authentication work using WCF bindings and contracts.
Using method GetToken we pass the following parameters: url, username and password to our Office365ClaimsConnector.MsOnlineClaimsHelper class that eventually will return our tokens to the service and back to our client.
The method GetDataFromSP is responsible for our query request, it accepts the following parameters: FedAuth,RtFa, url, search type and query. Basically we pass the 2 tokens to the CookieContainer object and finally to the HttpWebRequest object along with the url and the query. If our request succeeded we’ll get our search results in a nice JSON format.
Open the QueryStringHelper.cs file and add the following code.
using System.Collections.G
using System.L
using System.W
namespace Office365ClaimsService
public enum QueryType
public static class QueryStringHelper
public static Uri BuildQuery(QueryType type,string url,string query)
UriBuilder bldr = new UriBuilder(url);
switch (type)
case QueryType.Search:
///_api/search/query?querytext='search is cool'
string restQuery = &/_api/search/query&;
bldr.Path +=restQ
bldr.Query = &querytext='& + query + &'&;
case QueryType.Lists:
return bldr.U
I created this class for future implementation for other scenarios besides Search, like CRUD operations for lists etc..
Step 4: creating Login page
In “Win8AppForSharePoint& project Create a folder called pages and inside that folder create another folder called Login with 3 files: login.css ,login.html and login.js
Open the “login.html” file and add the following html.
&!DOCTYPE html&
&html xmlns=&http://www.w3.org/1999/xhtml&&
&meta charset=&utf-8& /&
&title&Connect to Sharepoint Online&/title&
&!-- WinJS references --&
&link rel=&stylesheet& href=&//Microsoft.WinJS.1.0.RC/css/ui-light.css& /&
src=&//Microsoft.WinJS.1.0.RC/js/base.js&&&/script&
src=&//Microsoft.WinJS.1.0.RC/js/ui.js&&
1: &/script&
&link rel=&stylesheet& href=&/pages/Login/login.css& /&
src=&/pages/Login/login.js&&
&!-- The content that will be loaded and displayed. --&
&div class=&detailPage fragment&&
&header role=&banner& aria-label=&Header content&&
&div class=&titleArea&&
&h1 class=&pageTitle win-type-xx-large&&&/h1&
&section role=&main& aria-label=&Main content&&
&h2 class=&title win-type-x-large&&&/h2&
&div class=&image&&&/div&
&div class=&content&&&/div&
&!-- input table --&
&table border=&0& style=&width: 252 height: 60px&&
&td&&label&Address:&/label&&/td&
&td&&input id=&address& type=&text&/&&/td&
&td&&label&Customer ID:&/label&&/td&
&td&&input id=&username& type=&text&/&&/td&
&td&&label&Password:&/label&&/td&
&td style=&height: 40px&&&input id=&password& type=&password&/&&/td&
&input class=&submitButton& type=&submit& name=&Submit& value=&Submit& /&
&progress class=&win-ring win-large progress&&&/progress&
&/article&
&/section&
The html file holds a simple table containing the login box that has Address, User id and Password. It also contains a hidden progress control (out of the box). I also added another class to hide the control and when the Login button is pressed and our request is sent to a remote server to get the access tokens, we’ll display the loading image.
&progress class=&win-ring win-large progress&&&/progress&
Open the “login.css” file and add the following css.
.detailPage section[role=main] {
-ms-grid-row: 2;
width: 100%;
height: 100%;
overflow-x:
.detailPage section[role=main] article {
column-fill:
column-width: 800
column-gap: 80
width: 800
margin-left: 120
.detailPage section[role=main] h1 {
margin-top: 0
margin-bottom: 20
.detailPage section[role=main] .image {
width: 800
height: 100
/*background: rgba(209, 211, 212, 1);*/
/*background: rgba(144, 178, 41, 1);*/
.detailPage section[role=main] p {
margin-right: 20
@media screen and (-ms-view-state: snapped) {
.detailPage .win-contentTitle {
font-size: 11
line-height: 15
.detailPage header[role=banner] {
display: -ms-
-ms-grid-columns: 44px 1
-ms-grid-rows: 1
.detailPage section[role=main] .image {
width: 260
height: 140
.detailPage section[role=main] article {
display: -ms-
-ms-grid-columns: 290px 1
-ms-grid-rows: 1
-ms-grid-row: 2;
width: 290
margin-left: 20
overflow-y:
overflow-x:
.progress {
The Login box:
Open the “login.js” file and add the following JavaScript code.
(function () {
// Track if the log in was successful
var loggedIn;
var localSettings = Windows.Storage.ApplicationData.current.localS
var containerName = &exampleContainer1&;
var nav = WinJS.N
&use strict&;
var page = WinJS.UI.Pages.define(&/pages/Login/login.html&, {
ready: function (element, options) {
element.querySelector('.submitButton').addEventListener('click', submitLogin, false);
function submitLogin() {
if (address|| username|| password)
//Creating message dialog box
var messagedialogpopup = new Windows.UI.Popups.MessageDialog(&Input can not be empty!&, &Error&);
messagedialogpopup.showAsync();
document.querySelector(&.progress&).style.display = &block&;
address = document.getElementById(&address&).
username = document.getElementById(&username&).
password = document.getElementById(&password&).
var json = JSON.stringify({ &url&: address, &userName&: username, &password&: password });
catch (err) {
WinJS.xhr({
type: &POST&,
url: &http://localhost:2738/Office365ClaimsService.svc/Authentication&,
headers: { &content-type&: &application/ charset=utf-8& },
data: json,
}).done(loginSuccess, loginFaliure, loginProgress);
function loginSuccess(request)
var obtainedData = window.JSON.parse(request.responseText);
var container = localSettings.createContainer(containerName, Windows.Storage.ApplicationDataCreateDisposition.always);
if (localSettings.containers.hasKey(containerName)) {
localSettings.containers.lookup(containerName).values[&FedAuth&] = obtainedData.FedA
localSettings.containers.lookup(containerName).values[&RtFa&] = obtainedData.RtFa;
localSettings.containers.lookup(containerName).values[&Url&] =
WinJS.Navigation.navigate('/pages/Search/search.html');
function loginFaliure(request)
document.querySelector(&.progress&).style.display = &none&;
//Creating message dialog box
var messagedialogpopup = new Windows.UI.Popups.MessageDialog(&An error occurred!&, &Error&);
messagedialogpopup.showAsync();
function loginProgress(request) {
object we basically get all html elements located on the page we requested. Using querySelector we get the Submit button element and add the EventListener for our button click. if one of the fields is empty we add
telling the user that his input is empty. After collecting the data (address, username, password) from the Login box, we create a JSON text using JSON.stringify and pass it to our WCF Authentication service, using
(callback). If we successfully logged-in we’ll get our two tokens/cookies “FedAuth” and “rtFa” that we’ll use for all of ours requests from SharePoint Online.
It’s worth mentioning that you can’t use “alert” for debugging or any pop-up notifications anymore as WinJS doesn’t support it. For debugging use
and for notification use .
We create our key in the Storage object we talked about, pass our tokens and url to the Storage object and navigate to Search page.
Step 5: creating Search page, Template and Binding
In “Win8AppForSharePoint& project create a folder called Search with 3 files: search.css ,search.html and search.js
Open the “search.html” file and add the following html.
&!DOCTYPE html&
&meta charset=&utf-8& /&
&title&SharePoint Search&/title&
&!-- WinJS references --&
&link href=&//Microsoft.WinJS.1.0.RC/css/ui-light.css& rel=&stylesheet& /&
&script src=&//Microsoft.WinJS.1.0.RC/js/base.js&&&/script&
&script src=&//Microsoft.WinJS.1.0.RC/js/ui.js&&
1: &/script&
&!-- Win8AppForSharePoint references --&
&link href=&/css/default.css& rel=&stylesheet& /&
&link rel=&stylesheet& href=&/pages/Search/search.css& /&
src=&/pages/Search/search.js&&
1: &/script&
&script src=&/js/default.js&&
1: &/script&
&script src=&/js/navigator.js&&
class=&content& aria-label=&Main content& role=&main&&
&img class=&spLogo& src=&../../images/sharepoint-logo.jpg& /&
&div id=&searchLbl&&SharePoint Online Search&/div&
&input id=&searchBox& name=&search& type=&text& placeholder=&Search...& /&
&button id=&searchBtn& type=&button&&Search&/button&
&div&&progress class=&win-ring win-large progress&&&/progress&&/div&
&div id=&searchResultsTemplate& data-win-control=&WinJS.Binding.Template&&
&div class=&itemResult&&
&div&&h2&&a class=&resultTitleLink& data-win-bind=&innerText:source: url&&&/a&&/h2&&/div&
&span& &a class=&resultUrl& data-win-bind=&innerText:source: url& &&/a&
&span class=&resultDate& data-win-bind=&innerText: date&&&/span&
&div class=&resultContent& data-win-bind=&innerText: content&&&/div&
&div id=&searchListView& data-win-control=&WinJS.UI.ListView&
data-win-options=&{itemTemplate:searchResultsTemplate,selectionMode:'none', layout: { type: WinJS.UI.ListLayout }}&&&/div&
The HTML will hold 3 section:
A) HTML elements containing our Search box and the “Search” button.
B) DIV marked with data-win-control=&WinJS.Binding.Template& attribute tells WinJS to treat it like a template, element marked with data-win-bind=& & attribute inside the template will help the binding engine to know which JavaScript properties from the data source to map to the appropriate HTML. Read more about it .
C) DIV marked with data-win-control=&WinJS.UI.ListView& attribute *transforms this simple DIV to JavaScript ListView control. inside the ListView Control we have another attribute called data-win-options=&{}& that we’ll use to tell the control which template to bind, which Layout etc.. Read more about it .
*This operations is done thanks to a JavaScript code:
Since we added the ListView to a , we don’t need to call WinJS.UI.processAll because the Page control does it for us.
Open the “search.css” file and add the following css.
#searchBox {
width: 500
height: 35
padding: 10px 20px 10px 10
margin: 1px auto 50
#searchLbl {
font-family:'Segoe UI Symbol';
font-weight:
text-align: padding-top: 50
.pagetitle{
.resultTitleLink{
text-decoration:
.resultAuthor{
.resultDate{
color:#777;
font-size:
.resultUrl{
color:#388222;
font-size:
.resultContent {
font-size:
height: 103
.progress {
margin: 1px auto 50
I also added an Office image and the Search box got a nice and simple search based UI:
Open the “search.js” file and add the following JavaScript code.
(function () {
&use strict&;
var localSettings = Windows.Storage.ApplicationData.current.localS
var containerName = &exampleContainer1&;
var searchResults = new Array();
var page = WinJS.UI.Pages.define(&/pages/Search/search.html&, {
ready: function (element, options) {
document.getElementById(&searchBtn&).addEventListener(&click&, getSearchData, false);
function getSearchData()
if (localSettings.containers.hasKey(containerName)) {
var FedAuth = localSettings.containers.lookup(containerName).values[&FedAuth&];
var RtFa = localSettings.containers.lookup(containerName).values[&RtFa&];
var Url = localSettings.containers.lookup(containerName).values[&Url&];
var Query = document.getElementById(&searchBox&).
if (Query == &&) {
//Creating message dialog box
var messagedialogpopup = new Windows.UI.Popups.MessageDialog(&Input can not be empty!&,&Error&);
messagedialogpopup.showAsync();
var lstView = document.getElementById(&searchListView&).winC
//clear array items
searchResults = [];
var dataList = new WinJS.Binding.List(searchResults);
lstView.itemDataSource = dataList.dataS
document.querySelector(&.progress&).style.display = &block&;
var json = JSON.stringify({ &FedAuth&: FedAuth, &RtFa&: RtFa, &url&: Url, &query&: Query });
WinJS.xhr({
type: &POST&,
url: &http://localhost:2738/Office365ClaimsService.svc/search&,
headers: { &content-type&: &application/ charset=utf-8& },
data: json,
}).done(processData, dataError);
function processData(response) {
document.querySelector(&.progress&).style.display = &none&;
var data = JSON.parse(response.response);
data = JSON.parse(data);
var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.
for (var i = 0, len = results. i & i++) {
var item = results[i].C
var date = new Date(item.results[8].Value);
var resultItem = {
author: item.results[4].Value,
title: item.results[3].Value,
date: date.toDateString(),
url: item.results[6].Value,
content: item.results[10].Value,
searchResults.push(resultItem);
var lstView = document.getElementById(&searchListView&).winC
var dataList = new WinJS.Binding.List(searchResults);
lstView.itemDataSource = dataList.dataS
function dataError(data)
document.querySelector(&.progress&).style.display = &none&;
//Creating message dialog box
var messagedialogpopup = new Windows.UI.Popups.MessageDialog(&Error!&, &Error&);
messagedialogpopup.showAsync();
After we got all the html elements using
object. we get the Search button element and add the EventListener for our button click. We grab all the data from our storage object using a key, of course if our query is empty we’ll throw a pop-up notifying the user .
Since our search data will change every time we click our search button we need to send an empty array list to ListView control to clear the data. we use a
that excepts our JavaScript array and connecting it to ListView itemDataSource to display the data. After collecting the data ( FedAuth,RtFa, url, query ) from the storage object, we create a JSON text using JSON.stringify and pass it to our WCF Search service we talked about earlier to pull data from SharePoint Online using Search REST API. If the operation succeeded we’ll get our JSON string, then we parse it and start populating the JavaScript list array, init our binding list with our data and connect it to ListView.itemDataSource to display the content that will be showed in a template we created on the HTML page.
The final result:
Step 6: Summary
Today we successfully created our Windows 8 App integrated with SharePoint Online services. We programmatically connected to SharePoint using Claims-based Authentication, got our data with the help of SharePoint search REST API and displayed our search results. Of course for displaying the search results I could iterate the JSON object and start appending the HTML elements but instead we used the Template and the Binding capabilities to render our data in an easy and simple way that WinJS offers us.
We’ve only seen the tip of the iceberg, Windows 8 app development is a rich and exciting world so I strongly advise you to start exploring it.
Soon we’ll try to extend this app to interact with the operation system.
You can download the full project on .
I hope this post was helpful .
You may also be interested in:
Editor’s note: Contributor Alex Choroshin is a Sharepoint Team Leader at . Follow him
The Planning Stage
There’s a big buzz going on around
app development, In my earlier post “” I showed how to create a metro live tile using html and JavaScript and today we continue exploring this subject area and create Windows 8 app that interacts with SharePoint.
We will focus on Windows 8 HTML5 app, There are 4 main reasons why I chose to use HTML5 development in this example.
SharePoint developers will feel much more comfortable around JavaScript and HTML rather then in XAML development.
Leverage your existing skills, Win 8 App uses Internet Explorer 10 engine that has extensive support for web standards like HTML5 and CSS3 that we can use in our App development to create rich native apps as described in
Create a *cross-platform application that can easily become a mobile app or even a SharePoint app.
HTML5 is the future so it’s best to always be up to date.
*When talking about Win8 HTML5 app and cross-platform it’s a bit tricky,why you ask?,Well Windows 8 introduced a new term called Windows Runtime or
, basically WinRT architecture gives us the ability to talk directly to window’s COM-based API, a privilege that only C++ programmers had. Of course C# and VB.NET programmers could use
to call the native API but it wasn’t an easy task and a significant overhead. Microsoft decided No more discrimination, C# and VB.NET, as well as JavaScript programmers now have the same power. With that said let’s get back to our cross-platform issue, it’s important to remember that you can use WinRT functionality only on Microsoft’s products like Windows 8 or Windows Phone so when you’re planning a cross-platform application maybe you should think using a cross-platform JavaScript libraries like ,
etc. but keep in mind that it always more preferable to use the native API.
In our example we plan to use
or “Microsoft Window Library for JavaScript SDK”. WinJS library offers us a similar development experience we get from Jquery and KnockoutJS, It provides a set of controls, a templating engine, a binding engine, promises to handle the asynchronous calls etc..
Part 2 is the development stage and we plan to create a working Windows 8 HTML5 app so see u next time.
You may also be interested in:
Editor’s note: Contributor Alex Choroshin is a Sharepoint Team Leader at . Follow him
One of the biggest changes made in SharePoint 2013 is the UI. And of course I’m talking about The Metro Ui Style.
We see it, feel it and interact with it since Microsoft introduced Windows phone 7 and later on in Windows 8 etc…
As stated on
“A key design principle of Metro is better focus on the content of applications, relying more on typography and less on graphics (&content before chrome&).”
More and more websites are adopting the Metro Ui Style, web sites like ,
and . plus more examples you can find .
We will focus on the Metro Live Tile. I decided to create a custom Live Tile using a JavaScript library that
created based on the ,
library that provides a template-based rendering that works great with JSON and the new SharePoint 2013 REST API that really makes our development experience much easier with CRUD operation using
and REST web technologies.
It’s worth pointing out that SharePoint 2013 has the option to
but I didn’t find a way of doing it programmatically. Nevertheless, it will be good practice for us to play a little bit with the JavaScript libraries and the new REST API as I mentioned before.
In our example we’ll create two tiles that read data from two lists. The first tile shows the pictures from the picture library and the second tile shows items from a list.
Let’s Begin
1) We will work with . Open VS2012 and create a new project. Choose Apps then App for SharePoint 2013 and call it “MetroStyleApp”.
2) Create a new folder and call it Lists, then add two lists. The first is a custom list, call it “CustomList” and the second is picture library, call it “pictureLibrary”.
3) Add three JavaScript files, ,
to the Scripts folder, and the MetroJs.css file to the Content folder.
4) Add the JavaScript and the css reference to PlaceHolderAdditionalPageHead in the Default.aspx
&script type=&text/javascript& src=&../Scripts/jquery-1.7.2.min.js&&&/script&
&script type=&text/javascript& src=&../Scripts/MetroJs.js&&&/script&
&script type=&text/javascript& src=&../Scripts/jsrender.js&&&/script&
&!-- Add your CSS styles to the following file --&
&link rel=&Stylesheet& type=&text/css& href=&../Content/App.css& /&
&link rel=&Stylesheet& type=&text/css& href=&../Content/MetroJs.css& /&
&!-- Add your JavaScript to the following file --&
&script type=&text/javascript& src=&../Scripts/App.js&&&/script&
<script type="text/javascript" src="../Scripts/jquery-1.7.2.min.js"></script>&&&& <script type="text/javascript" src="../Scripts/MetroJs.js"></script>&&&& <script type="text/javascript" src="../Scripts/jsrender.js"></script>&&&&<!-- Add your CSS styles to the following file -->&&&&<link rel="Stylesheet" type="text/css" href="../Content/App.css" />&&&& <link rel="Stylesheet" type="text/css" href="../Content/MetroJs.css" />&&&&<!-- Add your JavaScript to the following file -->&&&&<script type="text/javascript" src="../Scripts/App.js"></script>
Add the tiles html and the two Xsl List View web parts we created (pictureLibrary,CustomList) to the PlaceHolderMain.
&!-- Apply blue theme as default for all tiles --&
&h1&Live Tiles Example&/h1&
&div class=&tiles red&&
&div id=&tile1& class=&live-tile& data-initdelay=&4500&
data-delay=&2500& data-mode=&flip&&
&div&&p&This will be replaced
with items from the hidden &ul& with the
class'itemsSource'
&span class=&tile-title&&First Tile&/span&
item content will be here
&!-- im using a ul here, but this pattern can be used with div, p, span etc. --&
&ul class=&itemsSource&&
&div id=&tile2& class=&live-tile blue&
data-direction=&horizontal& data-initdelay=&500&
data-delay=&3000&&
&div class=&customList&&
&img class=&full&
src=/content/images/sample/1tw.gif
alt=&first& /&
&span class=&tile-title&&back title&/span&
&!-- Green Static Tile --&
&div class=&green live-tile&&
&span class=&tile-title&&static tile (figure 2d)&/span&
&p&Static tiles can take advantage of theming too!&/p&
&WebPartPages:WebPartZone runat=&server&
FrameType=&TitleBarOnly& ID=&full& Title=&loc:full& &
&WebPartPages:XsltListViewWebPart ID=&XsltListViewWebPart2& runat=&server&
ListUrl=&Lists/pictureLibrary& IsIncluded=&True&
NoDefaultStyle=&TRUE& Title=&pictureLibrary&
PageType=&PAGE_NORMALVIEW& Default=&False& ViewContentTypeId=&0x&&
&/WebPartPages:XsltListViewWebPart&
&WebPartPages:XsltListViewWebPart ID=&XsltListViewWebPart1&
runat=&server& ListUrl=&Lists/CustomList& IsIncluded=&True&
NoDefaultStyle=&TRUE& Title=&CustomList& PageType=&PAGE_NORMALVIEW&
Default=&False& ViewContentTypeId=&0x&&
&/WebPartPages:XsltListViewWebPart&
&/WebPartPages:WebPartZone&
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
<!-- Apply blue theme as default for all tiles --><h1>Live Tiles Example</h1><div class="tiles red">&&&& <div id="tile1" class="live-tile" data-initdelay="4500" data-delay="2500" data-mode="flip">&& &&&&&&&&<div><p>This will be replaced with items from the hidden <ul> with the class'itemsSource'&&&&&&&&&& <span class="tile-title">First Tile</span>&&&&&&&&&& </p>&&&&&&&&</div>&&&&&&&&<div>&&&&&&&&&&&&<p>&&&&&&&&&&&&&&&&item content will be here&&&&&&&&&&&&</p>&&&&&&&&</div>&&&&</div>&&&&<!-- im using a ul here, but this pattern can be used with div, p, span etc. -->&&&&<ul class="itemsSource">&&&&&& &&&&</ul>&& &&&&<div id="tile2" class="live-tile blue" data-direction="horizontal" data-initdelay="500" data-delay="3000">&&&& &&&&&&&&<div class="customList">&&&&&&&&&& &&&&&&&&</div>&&&&&&&&<div>&&&&&&&&&&&&<img class="full" src=http:///content/images/sample/1tw.gif alt="first" />&&&&&&&&<span class="tile-title">back title</span>&&&&&&&&</div>&& &&&&</div>&&&&& <!-- Green Static Tile -->&&&&<div class="green live-tile">&&&&&&&&<span class="tile-title">static tile (figure 2d)</span>&&&&&&&&<p>Static tiles can take advantage of theming too!</p>&&&&</div></div>&&<WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="full" Title="loc:full" ><WebPartPages:XsltListViewWebPart ID="XsltListViewWebPart2" runat="server" ListUrl="Lists/pictureLibrary" IsIncluded="True" NoDefaultStyle="TRUE" Title="pictureLibrary" PageType="PAGE_NORMALVIEW" Default="False" ViewContentTypeId="0x"></WebPartPages:XsltListViewWebPart>&<WebPartPages:XsltListViewWebPart ID="XsltListViewWebPart1" runat="server" ListUrl="Lists/CustomList" IsIncluded="True" NoDefaultStyle="TRUE" Title="CustomList" PageType="PAGE_NORMALVIEW" Default="False" ViewContentTypeId="0x"></WebPartPages:XsltListViewWebPart>&&&&&&&&&</WebPartPages:WebPartZone>
5)Add this Code to the app.js file. In this code you can see two REST API calls, first is to get all urls from the picture library and their ‘created’ date and the second is to get all the items from our custom list. Another thing you can see here is the two templates we created for each ajax call. And of course the cool use of the metroJS library.
function sharePointReady() {
requestPictureLibraryListItems();
requestCustomListItems();
$(&.green live-tile&).liveTile();
function requestPictureLibraryListItems()
var url = _spPageContextInfo.webAbsoluteUrl +
&/_api/web/lists/getbytitle('pictureLibrary')
/items?$select=EncodedAbsUrl,Created&;
jqxhr = $.getJSON(url, null, pictureDataReturned);
jqxhr.error(onError);
function requestCustomListItems() {
var url = _spPageContextInfo.webAbsoluteUrl +
&/_api/web/lists/getbytitle('CustomList')/items?$select=Title&;
jqxhr = $.getJSON(url, null, customDataReturned);
jqxhr.error(onError);
function pictureDataReturned(data)
$(&.itemsSource&).css(&display&,&none&);
var dataResults = data.d.
$.templates(&picturesTemplate&,
&&li&&img class='full'
src='{{:EncodedAbsUrl}}'&/&
&span class='tile-title'&Created:{{:Created}}&/span&&/li&&);
$(&.itemsSource&).append(renderPictureTemplate(dataResults));
//get the first item from the list
var $item = $(&.itemsSource&li&).first();
//set the back tile to have content of the first item by default
$(&#tile1&div&).last().html($item.html());
//set up tile
$(&#tile1&).liveTile({
pauseOnHover: true,
animationComplete: function (tileData, $front, $back) {
//get the next item from the list or the first
$item = $item.next(&li&);
if ($item.length == 0)
$item = $(&.itemsSource&li&).first();
$back.html($item.html());
function customDataReturned(data) {
var dataResults = data.d.
$.templates(&customListTemplate&, &&p&{{:Title}}&/p&&);
$(&.customList&).append(renderCustomTemplate(dataResults));
$(&#tile2&).liveTile(
mode: 'flip',
//choose images randomly from the array
backIsRandom: true
function renderPictureTemplate(data) {
html = $.render.picturesTemplate(data);
function renderCustomTemplate(data) {
html = $.render.customListTemplate(data);
function onError(error) {
alert(&error:&+JSON.stringify(error));
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
function sharePointReady() {&&&&requestPictureLibraryListItems();&&&&requestCustomListItems();&&&&&$(".green live-tile").liveTile();}function requestPictureLibraryListItems(){&&&&var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('pictureLibrary')/items?$select=EncodedAbsUrl,Created";&&&&jqxhr = $.getJSON(url, null, pictureDataReturned);&&&&jqxhr.error(onError);}function requestCustomListItems() {&&&&var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('CustomList')/items?$select=Title";&&&&jqxhr = $.getJSON(url, null, customDataReturned);&&&&jqxhr.error(onError);}function pictureDataReturned(data){&&&&$(".itemsSource").css("display","none");&&&&var dataResults = data.d.results;&&&&$.templates("picturesTemplate", "<li><img class='full' src='{{:EncodedAbsUrl}}'</><span class='tile-title'>Created:{{:Created}}</span></li>");&&&&$(".itemsSource").append(renderPictureTemplate(dataResults));&&&&//get the first item from the list&&&&var $item = $(".itemsSource>li").first();&&&&//set the back tile to have content of the first item by default&&&&$("#tile1&div&).last().html($item.html());&&&&//set up tile&&&&$("#tile1&).liveTile({&&&&&&&&pauseOnHover: true,&&&&&&&&animationComplete: function (tileData, $front, $back) {&&&&&&&&&&&&//get the next item from the list or the first&&&&&&&&&&&&$item = $item.next("li");&&&&&&&&&&&&if ($item.length == 0)&&&&&&&&&&&&&&&&$item = $(".itemsSource>li").first();&&&&&&&&&&&&$back.html($item.html());&&&&&&&&&}&&&&});}function customDataReturned(data) {&&&&var dataResults = data.d.results;&&&&$.templates("customListTemplate", "<p>{{:Title}}</p>");&&&&$(".customList").append(renderCustomTemplate(dataResults));&&&&$("#tile2&).liveTile(&&&&&&&&{&&&&&&&&&&&&mode: 'flip',&&&&&&&&&&&&//choose images randomly from the array&&&&&&&&&&&&backIsRandom: true&&&&&&&&}&&&&);&}function renderPictureTemplate(data) {&&&&var html;&&&&html = $.render.picturesTemplate(data);&&&&&&return html;}function renderCustomTemplate(data) {&&&&var html;&&&&&& html = $.render.customListTemplate(data);&& &&&&&& return html;}function onError(error) {&&&&alert("error:"+JSON.stringify(error));}
Deploy the project, add some pictures and a couple of items to the lists and then we’re done
Here’s the final result:
the full project.
See you next time.

我要回帖

更多关于 text rocketscript 的文章

 

随机推荐