Sitecore Forms + JSS + Angular
Sitecore Forms + JSS + Angular
I recently started working on a JSS project where the client had chosen to use Angular for their front-end framework. Part of this project requires the end-user to fill out a form to complete registration. Our initial approach for implementing this form was to build it out manually. However, there was a requirement to allow the content author to be able to control the information that is requested in the form. This to me screamed Sitecore Forms, and that is the direction I went. I almost immediately ran into a small problem: there is no Sitecore Forms implementation in JSS for Angular :(. There is an implementation via React. Time to create our own implementation to suit our needs. Most of the business logic (processing and submitting the form) will remain the same; what we have to implement is rendering support.
Disclaimer: There is a lot of code, and I am not likely going to put a lot in this post. I have my full implementation in a GitHub repository. I will be providing details on what was done with reference links to the appropriate locations in the repository.
To start out, I need to create a component that would render form data. The JSS documentation contains details on how to accomplish this.
- Create a new JSON Rendering - Form
- Update the Rendering Contents Resolver to use the Sitecore Forms Resolver
- Create a new angular component - jss scaffold form
- Register the component in your app module to tie back to your Form Rendering
One other thing the documentation says to do is add a code/pre tag containing the out for the forms data. This will be useful in helping to debug your code, but don't forget to remove or comment it out before you ship it.
Once I had my Forms data, I needed to figure out how to convert that to a form in Angular. Going into this adventure, I was (am) not well versed in Angular. The first thing I had to figure out how to do was generate a form based on a JSON object. For this, I found a handy blog post: Dynamic Forms In Angular. This post assumes that we are going to manually define our JSON object, but it is easy enough to adapt to account for the data being fed from another source. For brevity, I am only going to identity some key take-aways:
Component Per Field
You will need to create an Angular component for each field type you want to support in your forms. This is similar to what was done on the JSS React Forms implementation. I tried to implement the same components as the sample app. Each of the components can be found in my repository here.
Dynamic Field Directive
You will need to create a directive to translate the JSON data into the proper angular component. The dynamic-field.directive.ts has a field-id-type:component mapping. Each dataset that is passed in references the field type to construct and embed the appropriate component as-needed. Taking another page from the React sample implementation, the FieldTypes.ts are defined here. The translation directive can be found here.
Form Rendering "Engine"
The blog post has a separate app.component.ts and dynamic-form.directive.ts. This is not necessary for our use case. Most of the logic for the component and directive can be moved into the implementation for the form.component.ts that is scaffolded by JSS. The key thing for the component is the html that leverages the Dynamic Field directive to generate the fields:
<ng-template *ngFor="let field of form.fields;" dynamicField [tracker]="_tracker" [field]="field" [group]="formGroup"></ng-template>
This line iterates over all fields in your form, and converts each one to the appropriate component type to output on the screen. The individual component implementation can then take the data you pass in and render with class names and other properties as needed.
That is effectively everything that is needed to translate the forms data into something that will output as a form on the screen. There are a couple of other things to note before we call this done:
- replace-tag.directive.ts - the "Text" field in Sitecore Forms allows the content author to choose what tag will be used to render the text they enter. To accomplish this in Angular, it was necessary to create new directive that uses DOM manipulation to create the appropriate tag type when the component renders
- form-state.service.ts - the JSS React implementation takes advantage of a "state" property on components that does not exist in Angular. In an attempt to keep this implementation as closely aligned with the React implementation as possible, I leveraged an Angular service to track and apply the same changes that were being executed on the React side of things.
- SitecoreApiHost and SitecoreApiKey - these values are pulled from the generated environment.ts as a part of the application.
It took much longer than I would have liked to get the implementation up and running. As mentioned above, I was (and still am) not super well-versed with the workings of Angular. This implementation gave me a lot of opportunities to learn things about both Angular and JSS. Overall I am pretty happy with the end result and will continue to improve upon the implementation as there is a growing need to support additional features of Sitecore Forms.
You can check out all of the code for the implementation over on GitHub. I am available on the Sitecore Community Slack to answer questions, and will also do my best to keep up with issues/questions that come up on the repo.