Thursday 30 August 2012

Create lists, content types, fields etc. within a SharePoint 2013 app

Disclaimer: Just because I’m writing about apps, doesn’t mean I think everything in SP2013 should be developed as an app! I’m focusing on apps simply because it’s a deep area with lots to learn.

Recently I’ve been building a SharePoint 2013 app to help me learn the framework – specifically an on-premises app which has some SharePoint components, rather than a purely remote app. This series is based on some scenarios which I think are key building blocks for apps – for a given set of requirements, you’ll likely need to do one or more of these things. Frankly,you might need to do 100 other things too, but these are certainly common. Here’s a rough outline for the series (which I’ll probably tweak, and will definitely add to):

  1. SharePoint 2013 apps – architecture, capability and UX considerations
  2. Getting started – creating lists, content types, fields etc. within a SharePoint app (provisioning) [this article]
  3. Working with data in the app web, and why you should
  4. Access end-user data (in the host web) from a SharePoint 2013 app
  5. Rolling out SharePoint 2013 apps to the enterprise - tenant scope and PowerShell installs
  6. Azure is the new SharePoint ‘_layouts’ directory
  7. “Host web apps” – provisioning files (e.g. master pages) to the host web
  8. “Host web apps” – provisioning fields and content types
  9. Deploying SP2013 provider-hosted apps/Remote Event Receivers to Azure Websites (for Office 365 apps)
  10. Working with web parts within a SharePoint app

You’ll notice that I’m skipping setting up a SharePoint 2013 dev environment for developing apps. I think other folks have done a good job here – here are some good sources:

Before we start – understanding the ‘app web’ and security model

If you’re getting into developing apps for SharePoint, then I’m assuming you know something about the separation of apps and host webs. In a nutshell, apps are kept separate from ‘real’ end-user SharePoint sites – any lists and document libraries created by the app, any files and web pages, all live in a separate web application to the host site. When a user clicks on the app, they leave the host site behind and get redirected to a web which was created when the app was installed for this site. Effectively an ‘app web’ gets created for every site the app is installed to, in a structure which mirrors the host sites themselves.

Security is the primary driver behind this architecture – the app itself has Full Control over this specially-created site, but no rights (by default) to host sites. Clearly if a malicious app could delete end-user data, that would be A Very Bad Thing. Microsoft would not want that to happen, and so we have this separation. Additionally, it also serves to provide protection against cross-site scripting (IF the web application created for apps does not use the same domain or a subdomain – it should not), and allows SharePoint to identify the caller for Client Object Model calls.

UPDATE 17 Sept 2012: Actually there are circumstances where the developer *can* choose to have the lists/files/web pages etc. created in the host web rather than the app web. See the second half of the next article in this series Working with the app web, and why you should for discussion of this.

If you need more detail this host/app web split, then Ted Pattison has a nice post (in a great series) at SharePoint apps are isolated with respect to request processing and storage. You might not need to understand everything about this right now, but you shouldn’t ignore it.

Getting started– creating your first SharePoint-hosted app

Nothing too complex here – just fire up Visual Studio 2012 and create a project from the ‘App for SharePoint 2013’ project template:

CreateAppProject

You’ll then be asked to specify some settings for the app – here we need to tell Visual Studio which local site we’ll be developing against/deploying to, and that we are creating a SharePoint-hosted app:

SpecifyAppSettings

The project is created, and you’ll see that a bunch of files are added automatically – this is effectively a “Hello World” sample which is useful to get you started. jQuery is referenced, a Default.aspx page is added to the app, and this references a CSS file (App.css) and a JavaScript file (App.js) – the JavaScript file has some CSOM code to fetch the current user’s name and put it in a DIV on the page:

AppDefaultFiles

If you hit F5 to deploy this, you’ll see that the result is a pretty empty page which shows your app’s title (not yet converted to a user-friendly name in my case), and after a second or so for the AJAX call to complete, shows your username:

AppDefaultPage

At this point, it’s interesting to consider what this sample page does NOT have:

  • Any form of left-navigation/quick launch
  • Top navigation (although the more global strip in the chrome across the top exists)
  • Breadcrumb (although note the single link back to the host web, ‘Team 2’)
  • A Site Actions menu
  • A link to a Site Contents page (N.B. this page cannot be viewed in an app – if you try, you’ll get something like “The endpoint /team2/cobsharepointappsmyfirstapp/_layouts/15/viewlsts.aspx is not accessible in the context of a SharePoint App.”

So, it’s a pretty “bare bones” starting point. Now let’s take this towards something a bit more like a real-life app.

The concept - my "learner” time-recording sample app

To help us understand the app framework, let’s say we have to build some kind of time-recording app. Lots of us work in utilization-focused consulting organisations, so the concept of a timesheet is usually all too familiar.  The app I’m going to show won’t win any awards for functionality or design – and it definitely doesn’t provide enough end-user value to consider submitting it to the app store :) It’s purely to help me learn about apps, and I’d rather explore different areas even if the design is impractical or doesn’t really make sense.

Here’s what it currently looks like, though I’ll probably add bits to it over the course of this article series:

TimeTracking_SummaryUnderTarget 

TimeTracking_LogTime

TimeTracking_SummaryMetTarget 

App implementation

In terms of artifacts, some fundamental pieces of the app include:

  • Projects list
  • Logged time list
    • Uses TrackedTime content type – this defines 4 fields, including a lookup to Projects and a Person/Group field for employee
  • Utilisation targets (per employee) list
  • Default page
  • “My time summary” page – this is effectively a navigation-free version of Default.aspx
  • App part (ClientWebPart) to display “My time summary” page in host web

As I discussed in SharePoint 2013 apps – architecture, capability and UX considerations, it’s important to understand (or remember) is that with a couple of exceptions, a SharePoint-hosted app can only provision things into the automatically-created “app web”. This lives under the “apps” web application which must be created in an on-premises scenario. The diagram below tries to illustrate the breakdown between host site and app web – importantly, note that the “Utilisation targets” list in the host web was manually created outside of the app – purely because I wanted my app to include the scenario of working with data in the host web. In other words, you cannot usually get your app to provision a list in the host web. The only exception to this is if the app has Full Control to the host web, and some CSOM code runs to create this list - see Working with the app web, and why you should for discussion of this scenario. Note you can click on the image below to see a larger version:

TimeTrackingApp 

Provisioning lists, content types, site columns etc. within a SharePoint-hosted app

So the good news here is that there isn’t a huge amount of change if you’ve done these commonplace tasks in SharePoint 2010/Visual Studio 2010. That said, there are a couple of things which can throw you off track if you weren’t expecting them. The main difference of course, is that you’re not creating things in the actual site itself – and in the initial stages it’s tricky to know whether your artifacts are being provisioning successfully.

I’m not going to show the beginning-to-end process of deploying the above artifacts, but let’s look the outline. Depending on how you like to work, you might want to start with things like:

  • Rename ‘Feature1’ which was automatically added to your VS project, add a description etc.
  • Create some folders in your project if you prefer more structure than the default

Creating fields and content types

I created a TrackedTime content type with 4 fields. For my Projects list I didn’t actually define a custom content type – a simple list purely with a Title field sufficed.

  1. Right-click on the project in Solution Explorer, then select Add > New Item…
  2. From the Office/SharePoint category, select Site Column and name the item accordingly:

    CreateFields 
  3. Visual Studio will add some default XML for you. To define the 4 fields needed by my TrackedTime content type, I ended up with the following XML – note the lookup to the Projects list which is accomplished purely with declarative XML courtesy of the “List=’Lists/Projects’” on the 3rd field:
       1: <?xml version="1.0" encoding="utf-8"?>
       2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
       3:   <Field
       4:        ID="{ac8a5625-8769-4ed5-bfce-5ced1bfda792}"
       5:        Name="TimeTrackingEmployee"
       6:        DisplayName="Employee"
       7:        Type="User"
       8:        List="UserInfo"
       9:        Required="TRUE"
      10:        ShowField="ImnName" 
      11:        UserSelectionMode="PeopleOnly"
      12:        UserSelectionScope="0" 
      13:        Group="COB time-tracking site columns" />
      14:   <Field
      15:        ID="{CA358CA2-ED71-49D9-A05F-51C92B504062}"
      16:        Name="TimeTrackingDate"
      17:        DisplayName="Date"
      18:        Type="DateTime"
      19:        Format="DateOnly"
      20:        Required="TRUE"
      21:        Group="COB time-tracking site columns" />
      22:   <Field
      23:        ID="{ED1B7F0F-CACA-45A1-A0DD-8D0E6E604C5C}"
      24:        Name="TimeTrackingProjectName"
      25:        DisplayName="Project/task"
      26:        Type="Lookup"
      27:        List="Lists/Projects"
      28:        ShowField="Title"
      29:        Required="TRUE"
      30:        Group="COB time-tracking site columns" />
      31:   <Field
      32:        ID="{62D635BE-6481-4E2A-A6B6-4CDA40EAFB00}"
      33:        Name="TimeTrackingDuration"
      34:        DisplayName="Duration (hours)"
      35:        Type="Number"
      36:        Decimals="1"
      37:        Required="TRUE"
      38:        Group="COB time-tracking site columns" />
      39: </Elements>
  4. To make a content type using these fields, I then selected Add > New Item… and selected Content Type and named appropriately:

    CreateContentType1

    CreateContentType2 
  5. The next step is to add the fields we created to the content type. Visual Studio 2012 has a cool new Content Type Designer which appears here – simply start typing the name of the field, and VS scans fields from the SharePoint site it is connected to PLUS fields defined in the VS solution:

    VS2012ContentTypeDesigner
    Any fields added here will then be referenced as FieldRef elements in the content type XML behind the designer.

  6. Now we’re ready to provision a list based on this content type/set of fields. The initial steps are the same as you might be used to, but again we have a handy VS designer to help. Firstly we need to do an Add > New Item… and select List, then name appropriately:

    CreateList
    CreateList2 
  7. Now we see the new List Designer – if we wanted to add fields directly to the list rather than add a content type, we could use the main area of the Columns tab, but usually we’ll want to hit the ‘Content Types’ button:
     CreateList3
  8. In here, we can type the name of a content type already in the SharePoint site or within our VS solution:

    CreateList4
  9. Usually we’d also want to delete the Item and Folder content types, to leave just our custom content type with the fields:

    CreateList5
  10. The ‘Views’ tab within the list designer can then be used to add any custom views – in my case, I added one called ‘By employee’:

    CreateList6 
    N.B.  Unfortunately the designer doesn’t support all the things you might want to do, so in my case I had edit the XML by hand (the horror!) to actually implement the grouping. Still, this is all WAY better than we had before with SharePoint 2010 development.

  11. The final step is to ensure we’re happy with the top-level properties for the list, such as the title and URL. Take note of the URL the list will be provisioned to, you’ll need this soon:

    CreateList7 
  12. If we’re happy with the list, we can then test our app by hitting F5. When we click through to the app from the Site Contents page, we’ll be back here:

    AppDefaultPage
    At this point, the big question is…

“Where’s my list?!”

Of course, since there’s no default navigation in an app, it’s not immediately obvious if the list has been provisioned or not. However, if you’ve done the right things you’ll find your list is actually there. It’s tempting of course to try typing /_layouts/viewlsts.aspx in the URL bar, but as I mentioned earlier that’s not a page which can be used in an app.

Instead, just paste the URL of the list directly into the browser address bar after the app URL and you should be taken to your newly-provisioned list:

ProvisionedList

If you do not wish the list to be “hidden” (i.e. you want users to use it as a regular list), your next step will be to think about navigation – and what you’ll add to that default page so that users can get to the list.

Summary

So we now have a list which our app could use to store data. We could either allow end-users to access the list through the UI, use CSOM to read/write to it, or a combination of both. If you’ve created lists, content types etc. from Visual Studio in SharePoint 2010, you should find the process almost exactly the same – the main differences are the new VS designers and the fact that we’re provisioning to the app web.

Next time we’ll look at working with data in the app web.

7 comments:

Bhushan Gawale said...

Thanks much .. explained very well

Winson said...

I found out that the list could not look up the Title field of the 'Project' list. So, how could I provision the 'Project' list into the app web?

SkandaRamana said...

Instead of viewlsts.aspx an option we do have is /_layouts/15/mcontent.aspx, which while not same as viewing lists, does give us an indication of lists and direct access to the settings

canperk said...

Everything is fine when adding text or number fields. But there is something wrong when adding taxonomy field. It is not binding with termset

Chris O'Brien said...

@canperk,

Yes that's right - taxonomy fields need an extra step to bind them to their term set. As it happens, I wrote about this recently - see Three cloud-friendly ways for developers to provision Managed Metadata fields in SharePoint/Office 365

HTH,

Chris.

David Gumbleton said...

Hi Chris,

I hope all's well :) Thanks for writing this useful guide.

I'm having an issue with deploying a lookup field within a SharePoint hosted app solution. I have set the List="Lists/MyList" in the schema and ShowField="Title" as per your example above, but the field doesn't appear to be linked when it is deployed.

Could it possibly be an issue with me deploying both lists from the same feature?

Cheers

David

Chris O'Brien said...

Hi Dave!

The list where the lookup field is coming from definitely needs to exist when the other field gets provisioned. Usually this works fine if both things are in the same Feature - but since things to get processed in the order they come (in the Feature elements), you will want to ensure the other list is in a Feature element which is higher than the one which provisions the field.

Hope that makes sense :)

Cheers,

Chris.