SharePoint in Microsoft 365 is a fantastic resource for building company intranets, and a lot of functionality is available without significant customizations.

Even various templates are available through Microsoft’s SharePoint lookbook, showcasing commonly used examples.

One feature missing from the default templates is an announcement banner, a specific request for intranets. For example, companies may want to announce important information to their employees who are prominently featured on the intranet home page, such as an office closure due to weather or a reminder that timesheets are due.

There are examples of how to accomplish this in the SharePoint Patterns and Practices (PnP) GitHub repository (such as react-app-announcements), but this requires the development of a SharePoint Framework (SPFx) application customizer.

However, there is an easier way to display an announcement banner with less effort and without knowledge of SPFx.

A quick summary on how to accomplish this is to:

  • Set up a list in the intranet site to keep track of the announcements
  • Create a custom list view for showing current announcements
  • Use JSON formatting to modify that custom view
  • Place a list view web part on the intranet home page and point it to the custom view

Announcements List Setup

First, set up the announcements list.

From the home page of the intranet, choose “New” > “List” in the menu.

SharePoint Communication site

Then choose “Blank List.” In the dialog that appears, enter the list’s name (“Announcements”), add a description, and un-check the box to show in site navigation. Then press the “Create” button.

Company wide announcements

The new list is created, and the screen is redirected to the default list view.
Columns will need to be added to the list to track when to show the announcements.
Press “+ Add column,” then choose “Date and time.”

Create a Column for Values

In the slide-in panel for “Create a column,” enter and/or choose the following values for the column:

  • Name: Start Date
  • Description: The date that the announcement should begin displaying
  • Type: Date and time
  • Include Time: No
  • Friendly format: No
  • Default value: Today’s date

Apply details in created column

Then press the “Save” button to create the new column.

Next, press “+ Add column,” then choose “Date and time” again to add another column.

This time, enter and/or choose the following values for the column, then press the “Save” button to create the new column:

  • Name: End Date
  • Description: The date that the announcement should stop displaying
  • Type: Date and time
  • Include Time: Yes
  • Friendly format: No
  • Default value: None

Create an End Date Column

Another column to define the type of announcement should also be created. This will also determine the icon and color that is displayed for the announcement.

Press “+ Add column,” then choose “Choice.”

Enter and/or choose the following values for the column:

  • Name: Announcement Type
  • Description: The type of announcement to display: Notice = Blue, Warning = Yellow, Alert = Pink
  • Type: Choice

For the Choices section, edit the existing three choices to be:

  • Notice
  • Warning
  • Alert

Change the color of the “Warning” choice by pressing the palette icon and choosing the “Gold” color.

Change the color of the “Alert” choice by pressing the palette icon and choosing the “Peach” color.

Customize Column Color

Select “Notice” to be the Default value, then press “More options” to make further adjustments to the column.

Choose Options for the Column

Choose the following options for the column, then press “Save” to create it.

  • Display choices using: Radio Buttons
  • Allow multiple selections: No
  • Require that this column contains information: No
  • Enforce unique values: No
  • Add to all content types: Yes

Create a section for a link

The last column to add should be a link if the announcement has more information that the user needs to reference.

Press “+ Add column,” then choose “Single line of text.” Enter and/or choose the following values for the column, then press the “Save” button to create the new column:

  • Name: Announcement Link
  • Description: Link for more information
  • Type: Single line of text
  • Default value: #

Creating an Announcement Column

The Announcements list should now have all the columns needed:

  • Title
  • Start Date
  • End Date
  • Announcement Type
  • Announcement Link

Custom View for Announcements List

Next, a custom view of the Announcements list should be created to display current announcements.

On the right side of the list menu bar, press the “All Items” button, then choose “Create new view”.

New View Creation

In the dialog, enter “Current Announcements” for the View name, keep “Make this a public view” checked, then press “Create.”

Current Announcements

It should redirect to the Current Announcements list view. On the right side of the list menu bar, press the “Current Announcements” button, then choose “Edit current view.”

Edit Current Column View

In the “Columns” section, make sure the following columns are checked, to include them in the view:

  • Title
  • Start Date
  • End Date
  • Announcement Type
  • Announcement Link

Make sure columns are checked

In the “Sort” section, set the first sort to “End Date” and “Show items in descending order,” then set the second sort to “Start Date” and “Show items in descending order.”

Sort the Column by End Date

In the “Filter” section, set the filter to show items when “Start Date” is less than or equal to “[Today]” AND when “End Date” is greater than or equal to “[Today].”

Customize the Filter Section

Scroll down and press the “OK” button to finish editing the view.

Custom View Formatting

Before applying some custom formatting to the view, enter a few items into the list for testing purposes.

To see the items in the view, make sure that for each item, the “Start Date” is less than or equal to today’s date, and the “End Date” is greater than or equal to today’s date. Then, choose at least one of each “Announcement Type” to see how the formatting changes for each type.

An example is below:

  • Title: Timesheets Due by COB 10/31/2021
  • Start Date: 10/26/2021
  • End Date: 11/1/2021 12:00 AM
  • Announcement Type: Warning
  • Announcement Link: #

Timesheets Due and Announcement Link

If the announcement banner should link to somewhere else, enter a full URL into the “Announcement Link” field.

After entering a few items into the list, it should look something like this:

Populated List

On the right side of the list menu bar, press the “Current Announcements” button, then choose “Format current view.”

Current View Format

In the sidebar, scroll down and choose “Advanced mode”.

Advanced Mode

The sidebar will now show an input field that contains JSON code. Copy the code from that field and paste it into a preferred code editor to make it easier to work with.

Format View

Microsoft has some great examples of list view formatting. Let’s walk through the formatting for this example.

Since this view will only show a banner, the list headers and the selection options should be hidden, so “hideSelection” and “hideColumnHeader” should be set to true.

Instead of the traditional table elements, we will use the “rowFormatter” to render custom elements per row/item.

In the row formatter, we should first determine what type the element should be, set by the “elmType” property. In this case, we will set it to a “div”.

Next, we will apply CSS class attributes to that div element based on certain conditions. There are many predefined CSS class names that SharePoint uses, which we can apply to the div. A few of the common ones are listed in their style guidelines.

The condition we want to check is the value of the “Announcement Type” column. When referencing a list column in JSON, enclose it in “[]” brackets, and prepend it with “$”. (Depending on the name of the column, sometimes spaces may also need to be substituted with “_x0020_”.)

In the code snippet shown, we check the following conditions and apply the appropriate CSS classes to the div based on that condition.

Announcement Type

{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/row-formatting.schema.json",
  "hideSelection": true,
  "hideColumnHeader": true,
  "rowFormatter": {
    "elmType": "div",
    "attributes": {
      "class": "=if([$AnnouncementType] == 'Notice', 'sp-row-card sp-field-severity--low', if([$AnnouncementType] == 'Warning', 'sp-row-card sp-field-severity--warning', if([$AnnouncementType] == 'Alert', 'sp-row-card sp-field-severity--severeWarning', '')))"
    },
    "children": [
    ]
  }
}

Next, we will specify how the child elements of the div are rendered. Under the “children” property, we will set up two span elements inside the div: One for the icon and one for the text.
For the span element with the icon, first, we set up an “elmType” of “span”. Then we check the “Announcement Type” column again to reference the name of the icon from the Fluent UI library and apply it to the “iconName” attribute under “attributes.”

Attributes

We can also apply specific CSS styles to that span via the “style” property. Here we use custom padding, display, and font-size style attributes.

{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/row-formatting.schema.json",
  "hideSelection": true,
  "hideColumnHeader": true,
  "rowFormatter": {
    "elmType": "div",
    "attributes": {
      "class": "=if([$AnnouncementType] == 'Notice', 'sp-row-card sp-field-severity--low', if([$AnnouncementType] == 'Warning', 'sp-row-card sp-field-severity--warning', if([$AnnouncementType] == 'Alert', 'sp-row-card sp-field-severity--severeWarning', '')))"
    },
    "children": [
      {
        "elmType": "span",
        "attributes": {
          "iconName": "=if([$AnnouncementType] == 'Notice', 'Info', if([$AnnouncementType] == 'Warning', 'Error', if([$AnnouncementType] == 'Alert', 'Warning', '')))"
        },
        "style": {
          "padding-right": "12px",
          "display": "inline-block",
          "font-size": "1.5em"
        }
      }
    ]
  }
}

Next to the span with the icon, we will render another span with the “Title” text for that announcement item. It should be set as an “elmType” of “span.” Custom display and vertical-align styles can be applied with the “style” property. To render the title text, set the “txtContent” property to “[$Title]”.

{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/row-formatting.schema.json",
  "hideSelection": true,
  "hideColumnHeader": true,
  "rowFormatter": {
    "elmType": "div",
    "attributes": {
      "class": "=if([$AnnouncementType] == 'Notice', 'sp-row-card sp-field-severity--low', if([$AnnouncementType] == 'Warning', 'sp-row-card sp-field-severity--warning', if([$AnnouncementType] == 'Alert', 'sp-row-card sp-field-severity--severeWarning', '')))"
    },
    "children": [
      {
        "elmType": "span",
        "attributes": {
          "iconName": "=if([$AnnouncementType] == 'Notice', 'Info', if([$AnnouncementType] == 'Warning', 'Error', if([$AnnouncementType] == 'Alert', 'Warning', '')))"
        },
        "style": {
          "padding-right": "12px",
          "display": "inline-block",
          "font-size": "1.5em"
        }
      },
      {
        "elmType": "span",
        "style": {
          "display": "inline-block",
          "vertical-align": "top"
        },
        "txtContent": "[$Title]"
      }
    ]
  }
}

Select the code above and copy it. Go back to the editor for the custom view formatting ( “Current Announcements” > “Format current view” > “Advanced mode”) and paste the code into the JSON code editor.

Format View List Layout

Press the “Save” button, and the “Current Announcements” list view should now look similar to this:

List View for Announcements

We may want to change the background color for notices to the same color chosen when creating the choices for the column. To do that, change “sp-field-severity–low” in the div’s class attribute to “sp-CSS-backgroundColor-BgCornflowerBlue.” Once that change is made to the code in the custom view formatting and “Save” is pressed again, any “Notice” announcements should now have a light blue background.

This looks great for basic announcements, but what if users need to link to an article or website for more information? To do that, we will need to take the current span children of each row and move them inside an anchor element used for the link.

Create a new “elmType” of “a” as the first object inside the main div’s “children” property. Set the anchor’s “href” attribute to reference the “Announcement Link” column, and apply a condition to set the anchor’s “target” attribute. We want the link to open in a new window if it is not the default “#” value. Next, add custom “style” properties to set the display, text-align, font-size, text-decoration, and color, then add an empty “children” property, where we will move the current icon and text spans.

{
        "elmType": "a",
        "attributes": {
          "target": "=if([$AnnouncementLink]!='#','_blank','_self')",
          "href": "[$AnnouncementLink]"
        },
        "style": {
          "text-align": "left",
          "font-size": "1.3em",
          "text-decoration": "none",
          "color": "#212121",
          "display": "block"
        },
        "children": []
      }, 

Now move the original child “span” elements into the children of the “a” element. The final code should look like this:

{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json",
  "hideSelection": true,
  "hideColumnHeader": true,
  "rowFormatter": {
    "elmType": "div",
    "attributes": {
      "class": "=if([$AnnouncementType] == 'Notice', 'sp-row-card sp-CSS-backgroundColor-BgCornflowerBlue', if([$AnnouncementType] == 'Warning', 'sp-row-card sp-field-severity--warning', if([$AnnouncementType] == 'Alert', 'sp-row-card sp-field-severity--severeWarning', '')))"
    },
    "children": [
      {
        "elmType": "a",
        "attributes": {
          "target": "=if([$AnnouncementLink]!='#','_blank','_self')",
          "href": "[$AnnouncementLink]"
        },
        "style": {
          "text-align": "left",
          "font-size": "1.3em",
          "text-decoration": "none",
          "color": "#212121",
          "display": "block"
        },
        "children": [
          {
            "elmType": "span",
            "attributes": {
              "iconName": "=if([$AnnouncementType] == 'Notice', 'Info', if([$AnnouncementType] == 'Warning', 'Error', if([$AnnouncementType] == 'Alert', 'Warning', '')))"
            },
            "style": {
              "padding-right": "12px",
              "display": "inline-block",
              "font-size": "1.5em"
            }
          },
          {
            "elmType": "span",
            "style": {
              "display": "inline-block",
              "vertical-align": "top"
            },
            "txtContent": "[$Title]"
          }
        ]
      }
    ]
  }
}

Paste this updated code into the editor for the custom view formatting ( “Current Announcements”
> “Format current view” > “Advanced mode”), and press the “Save” button once again.

Current Announcements

The “Current Announcements” list view should now look similar to this:

Current Announcement Views

Display List View on Home Page

Now that the list view has been formatted as desired, it can be added to the intranet home page.

Go to the intranet home page and press the “Edit” button in the toolbar to edit the page.

Edit Current View

Hover over a prominent area on the page where the announcements should go, then press the “+” button to add a new web part there.

Add new web part

Scroll down to the “Documents, lists, and libraries” section in the menu and choose the “List” web part.

Choose the List web part

When the web part is added to the page, it will prompt for which list to select. Choose the “Announcements” list.

Announcements

By default, the List web part displays the All Items list view. Hover over the pencil icon next to the web part to edit its properties.

Edit Announcements List

In the slide-in panel, select the “Current Announcements” view, toggle the switch to the “Hide command bar,” then press the “Apply” button.

Current Announcements

The List web part should now display the formatted “Current Announcements” view without additional list command bar controls.

Web Part List

In the page toolbar, press the “Save as draft” button to save the updates, then press “Republish” to publish the new version of the home page.

Save as a Draft

Now important company announcements are displayed on the intranet home page in a prominent location.

Republish

Conclusion

This is just one example of how a low-code solution with relatively little effort can be implemented to satisfy the need for a custom feature not natively provided by SharePoint.
For additional resources and other examples, refer to Microsoft’s documentation on list formatting.

AIS has tons of experience helping companies build useful intranets. Contact us to see how we can help.

How to use galleries to create dynamic entries in a data source in Power Apps

In this article, we will see how we can use galleries in Power Apps to create multiple rows for adding records to a data source. We will create dynamic entries in a gallery that looks like a form and adds/deletes a line/row with the press of a button.

Scenario: XYZ Inc. is a sales company that deals in sales of hardware components from manufacturers to retailers. User A is an on-field sales agent of XYZ Inc. and uses a static application to enter the order details from a customer. This application is further connected to a SharePoint list and creates a new item on the list whenever User A enters the detail and hits the submit button. The application provides the ability to enter only one order detail at a time and User A ends up putting more effort and time in entering those details.

We designed a customized Power App for XYZ Inc. where User A authenticates and lands on the Order Details page. User A can view all their previous entries, search for an order by entering the name of the customer, vendor, invoice number, etc. Functionality to add details is provided within the app. User A clicks the add new orders button and a form gallery is displayed. User A can add multiple records by creating new lines with the press of a button in the form gallery. A local collection with all the entries on the form is created in Power Apps. Once User A hits the “Finish & Save” button, an item for each entry is created on the SharePoint List and the Order Details gallery is updated with these newly added records.

Let’s look at the component-wise description of the controls in the app. The schema for data on the SharePoint List is:

S.No Column Name Column Data Type
1 Title (Order Number) Single Line of Text (255 Chars)
2 Customer Single Line of Text (255 Chars)
3 Shipping Address Single Line of Text (255 Chars)
4 Billing Address Single Line of Text (255 Chars)

On the App -> OnStart option, the expression used is:

ClearCollect(DynamicGallery,{Value:1}); Clear(OrderCollection); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order1"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order2"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order3"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order4"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order5"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order6"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order7"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order8"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order9")))

Explanation: Here, I am creating a collection “Dynamic Gallery” and this is the number of rows corresponding to the gallery control for creating the new orders. I am creating another collection “OrderCollection” and this collection contains all the Order Details from the SharePoint List named “OrderDets”.

Note: The “StartsWith” function is not delegable if a variable is passed as the second argument which is the reason why I am using multiple “Collect” statements to iterate over all possible values.

Galleries to create dynamic entries in a Data Source in PowerApps1

  1. This icon is the Home Page icon and clicking on this navigates the user to the home screen
  2. This icon is the Order Details Screen icon and clicking on this navigates the user to the Order Details Screen
  3. This icon is the Edit an Item icon and clicking on this allows the user to edit a particular item
  4. This icon is the Refresh Icon and clicking on this refreshes the data source, the expression used here is:

Refresh(OrderDets);Clear(OrderCollection); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order1"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order2"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order3"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order4"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order5"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order6"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order7"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order8"))); Collect(OrderCollection,Filter(OrderDets,StartsWith(Title,"Order9")))

Explanation: This refreshes the data source (“OrderDets” SharePoint List). It also clears the existing data from the “OrderCollection” collection and refills it with the new data.

  1. This is a gallery control that populates all the items of the SharePoint list
    • The expression used in the “Text” property of the “Order Details” label is:

"Order Details Total Orders Count:"&CountRows(OrderCollection)

Explanation: This expression concatenates the simple text (wrapped in “”) with the integer returned as a result of the “CountRows” function applied on the “OrderCollection” collection.

    • The expression used in the “Items” property of the Gallery is:

Sort(Filter(OrderCollection,If(!IsBlank(TextInput3.Text),StartsWith(Title,TextInput3.Tex t) ||
StartsWith(Customer,TextInput3.Text),true)),Value(Last(Split(Title,"r")).Result),Descen ding)

  1. This is a stack of Text labels used to show the information when an item is selected in the “Order Details” gallery. Expressions used on the labels:

Customer: Gallery5.Selected.Customer, Shipping Address: Gallery5.Selected.'Shipping Address', Billing Address: Gallery5.Selected.'Billing Address'

Explanation: Each line is an individual expression that fetched the attributes of the item selected in the “OrderDetails” gallery (Gallery5).

  1. This is a button control that enables the gallery control for the user to create dynamic lines and enter the order details. Expression used on this button:

ClearCollect(DynamicGallery,{Value:1});Set(NewOrder,true);Set(ResetGallery,false);Set(ResetGallery,true)

Explanation: Here I am recreating the “DynamicGallery” collection to accommodate just one value that corresponds to one row of the newly visible dynamic control gallery. I am setting up two new variables “NewOrder” and “ResetGallery” that control the visibility/reset of this dynamic gallery control, “Total Number of New Orders” and the “Finish and Save Button” controls.

Use Galleries to create dynamic entries in a Data Source in PowerApps 2

  1. This is the dynamic gallery control that I customized for user inputs. This gallery control has four text input controls to get the values for each of the attributes of the SharePoint List. The user can create multiple lines (one at a time) to add multiple records in one go. Data from each line is directly patched to the data source to create a new item. The user can remove the line by clicking the “X” icon. Configuration of the elements of the gallery control:

Gallery Properties:
Items: DynamicGallery, Visible: NewOrder,

Explanation: “DynamicGallery” is the collection that holds count of the orders to be added. “NewOrder” is a variable used to set the visibility of the controls.

  1. This icon is to remove the current row from the dynamic gallery. The expression used on this is:

Icon Properties:
OnSelect: Remove(DynamicGallery,ThisItem), Visible: If(ThisItem.Value <>
Last(Sort(DynamicGallery,Value,Ascending)).Value,true,false)

Explanation: We are removing the current item from the gallery by pressing this button (“OnSelect”) property. This icon’s visibility is set in a way that it shows up only if the current row is not the last item of the dynamic gallery.

  1. This icon is to add a new row/ line to the dynamic gallery. The expression used on this is:

Icon Properties:
OnSelect: Collect(DynamicGallery,{Value: ThisItem.Value + 1}), Visible: If(ThisItem.Value =
Last(Sort(DynamicGallery,Value,Ascending)).Value,true,false)

Explanation: We are adding a row/line by adding an item to the dynamic gallery collection by pressing this button (“OnSelect”) property. This icon’s visibility is set such that it shows up only on the last item of the dynamic gallery.

  1. This button is to perform the patch action on the “OrderDets” SharePoint List and it patches all the entries made by the User A in the dynamic gallery. The expression used in this control is:

ForAll(
Gallery3_1.AllItems,
Concurrent(
Patch(OrderDets,Defaults(OrderDets),{Title:TextInput2_6.Text,Customer:TextInput2 _7.Text,'Shipping Address':TextInput2_4.Text,'Billing Address':TextInput2_5.Text}), Patch(OrderCollection,Defaults(OrderCollection),{Title:TextInput2_6.Text,Customer: TextInput2_7.Text,'Shipping Address':TextInput2_4.Text,'Billing
Address':TextInput2_5.Text})));
ClearCollect(DynamicGallery,{Value:1});
Set(NewOrder,false);
Refresh(OrderDets)

Explanation: In this control, the concurrent function executes two patch commands, one in the data source (“OrderDets” SharePoint List) and the other on the local collection (“OrderCollection”) based on the inputs by the User A in each of the line/ row of the dynamic gallery. The “DynamicGallery” collection is being reset to hold a single value. The variable “NewOrder” is set to “false” to toggle the visibility of the dynamic gallery and then we finally refresh the data source.

Note: We are doing a concurrent patch instead of refreshing and recollecting the data in the collection “OrderCollection” from the data source to optimize the operations in the app.

  1. This is the text label control that displays the total number of current lines/rows User A has created. The expression used here is:

"Total Number of New Orders: "& CountRows(Gallery3_1.AllItems)

Explanation: Here the text “Total number of New Orders” is being concatenated with the number of rows of the dynamic gallery.

Use Galleries to create dynamic entries in a Data Source in PowerApps 3

  1. This is the text input control of the dynamic gallery. Here I am validating the text input and checking through the “OrderCollection” if the entered Order Number already exists. If it exists, the user will get an error notification. The expression used in the “OnChange” property of this control is:

If(TextInput2_6.Text in OrderCollection.Title,Notify("Order Number already exists!",NotificationType.Error))

Explanation: Here the if condition checks if the text of the text input control exists in the “Title” column of the “OrderCollection” collection and pops an error message if the condition is met.

  1. This is the error notification generated when the user enters an existing order number in the text input.

Use Galleries to create dynamic entries in a Data Source in PowerApps 4

  1. This is the App settings page of the app where we are increasing the soft limit of the data row limit on of non-delegable queries from 500 to 2000.

In this article, I have shown a basic implementation of the dynamic galleries concept and the multiple items/ records patch function for a SharePoint data source. This can be replicated with minor changes in the expressions for other data sources such as CDS, excel, SQL, etc.

I hope you found this interesting and it helped you. Thank you for reading!