Configuration

Configuration can seem daunting, but to create your first Archetype, do the the following:

  • Navigate to Developer->Data Type
  • Right click and create a new data type.
  • Select Archetype from the dropdown.
  • Name your fieldset
  • Give your fieldset an alias (or accept the default)
  • Add one or more properties
  • Each property needs a name, an alias and a data type

That is all that is required.

config

Tick the Toggle Advanced Options box to expose advanced options.

Add to a Document Type

Once configured, navigate to Settings->Document Types and add the new data type to a document type.

Multiple Fieldsets

You can enable multiple fieldsets in a single Archetype by going into the advanced options and ticking Enable Multiple Fieldsets?.

This will expose a hidden plus sign that allows that you’ll need to click to add another fieldset type. It also allows you to choose an installed icon to separate the two types visually once added to a document type.

Nested Archetypes

You can nest Archetypes within Archetypes; they can even reference themselves (supposing you also start with the add button to avoid infinite nesting).

Cross-Archetype Dragging

To allow for Archetype fieldsets to be dragged between Umbraco properties and into/out of nested Archetypes, check the “Enabled Cross-Archetype Dragging” configuration option.

Once enabled, you will be able to drag compatible Archetype fieldsets to other Archetypes, whether they are entirely different properties or they are nested Archetypes:

Cross-Archetype Dragging Example Animation

Label Template

You can configure Archetype to show a value from inside your Archetype to be shown on the collapsed fieldset title.

Typically you would use this syntax in the Label Template box: {{propertyName}}.

You can pass in a custom function into the label with the following syntax {{myFunction(propertyName)}}.

You can pass args to your label template too, please keep reading thru the examples if interested.

Make sure your function is available to Umbraco by adding your custom code to a package manifest.

Promises and Dependency Injection in Label Templates

Starting with Archetype 1.16.0, you can create label template functions that return promises and that support injection of AngularJS dependencies. This comes in handy for more advanced scenarios, such as when you need to perform asynchronous operations like getting data from the web server.

In most instances where you would use a promise, you will also want to inject an AngularJS dependency that has a function that returns a promise. So, you’ll first want to know how to have dependencies injected. You can do so like this:

  1. function archetypeGetNodeUrl(value) {
  2. return function (contentResource) {
  3. /* Your code here. */
  4. };
  5. }

That will allow you to inject the contentResource service. All you need to do in order to have a dependency injected is return a function with that dependency as one of the parameters.

Taking this example further, you could then return a promise from the function:

  1. function archetypeGetNodeUrl(value) {
  2. return function (contentResource) {
  3. if (!value) {
  4. return "Unknown URL";
  5. }
  6. return contentResource.getById(value)
  7. .then(function (response) {
  8. return response.urls[0] || "Unknown URL";
  9. });
  10. };
  11. }

You will likely want to add some caching so subsequent requests to your function don’t initiate server-side calls every time it is called. Here’s an example of how you might go about that:

  1. function archetypeGetNodeUrl(value) {
  2. return function (contentResource) {
  3. if (!value) {
  4. return "Unknown URL";
  5. }
  6. archetypeGetNodeUrl.cache = archetypeGetNodeUrl.cache || {};
  7. if (archetypeGetNodeUrl.cache[value]) {
  8. return archetypeGetNodeUrl.cache[value];
  9. }
  10. return contentResource.getById(value)
  11. .then(function (response) {
  12. archetypeGetNodeUrl.cache[value] = response.urls[0] || "Unknown URL";
  13. return archetypeGetNodeUrl.cache[value];
  14. });
  15. };
  16. }

The above code can also be rewritten like so and it would function the same way, though perhaps slightly faster:

  1. function archetypeGetNodeUrl(value) {
  2. if (!value) {
  3. return "Unknown URL";
  4. }
  5. archetypeGetNodeUrl.cache = archetypeGetNodeUrl.cache || {};
  6. if (archetypeGetNodeUrl.cache[value]) {
  7. return archetypeGetNodeUrl.cache[value];
  8. }
  9. return function (contentResource) {
  10. return contentResource.getById(value)
  11. .then(function (response) {
  12. archetypeGetNodeUrl.cache[value] = response.urls[0] || "Unknown URL";
  13. return archetypeGetNodeUrl.cache[value];
  14. });
  15. };
  16. }

This demonstrates that you can return different types of objects from your function at different times. In the case of a cache hit, this will return a string. In the case of a cache miss, this will return a function that will return a promise that will resolve to a string.

Here is a heavily commented version of the above function, which should help you to understand what each line is doing:

  1. /**
  2. * This function will be called from an Archetype label template, and it will eventually
  3. * resolve to a string that is the URL of the supplied content node ID.
  4. * @param value The content node ID.
  5. * @returns {*} A string or a function. In the case of a function, it will be called and
  6. * will subsequently return a promise. That promise will then eventually resolve to
  7. * a string value.
  8. */
  9. function archetypeGetNodeUrl(value) {
  10. // If the supplied value is falsy (e.g., null or undefined), return early.
  11. if (!value) {
  12. return "Unknown URL";
  13. }
  14. // Ensure the cache has been initialized.
  15. archetypeGetNodeUrl.cache = archetypeGetNodeUrl.cache || {};
  16. // If the node is already in the cache, return the URL from the cache.
  17. if (archetypeGetNodeUrl.cache[value]) {
  18. return archetypeGetNodeUrl.cache[value];
  19. }
  20. // Return a function that will be called and have its dependencies injected.
  21. return function (contentResource) {
  22. // Call Umbraco's contentResource service. Specifically, the getById function,
  23. // which will return information about a content node by its ID. This will return
  24. // a JavaScript promise.
  25. return contentResource.getById(value)
  26. // Now that getById has returned a promise, we will process the result of that
  27. // promise and return yet another promise that will eventually resolve to a
  28. // string.
  29. .then(function (response) {
  30. // Store the URL to the cache, then return it.
  31. archetypeGetNodeUrl.cache[value] = response.urls[0] || "Unknown URL";
  32. return archetypeGetNodeUrl.cache[value];
  33. });
  34. };
  35. }

Addtional Samples

  1. //create a namespace (optional)
  2. var ArchetypeSampleLabelHelpers = {};
  3. //create a function
  4. //you will add it to your label template field as `{{ArchetypeSampleLabelHelpers.testPromise(someArchetypePropertyAlias)}}`
  5. ArchetypeSampleLabelHelpers.testPromise = function(value) {
  6. //you can inject services
  7. return function ($timeout, archetypeCacheService) {
  8. //best to return a promise
  9. //NOTE: $timeout returns a promise
  10. return $timeout(function () {
  11. return "As Promised: " + value;
  12. }, 1000);
  13. }
  14. }
  15. ArchetypeSampleLabelHelpers.testEntityPromise = function(value, scope, args) {
  16. //hey look, args!
  17. //{{ArchetypeSampleLabelHelpers.testEntityPromise(someArchetypePropertyAlias, {foo: 1})}}
  18. console.log(args);
  19. return function ($q, entityResource) {
  20. var deferred = $q.defer();
  21. entityResource.getById(args.foo, 'document').then(function(entity) {
  22. console.log("Hello from testEntityPromise");
  23. console.log(entity);
  24. deferred.resolve(entity.name);
  25. });
  26. return deferred.promise;
  27. }
  28. }
  29. ArchetypeSampleLabelHelpers.testEntityPromise2 = function(value, scope, args) {
  30. //hey look, args but we're also using the built-in archetypeCacheService
  31. //{{ArchetypeSampleLabelHelpers.testEntityPromise(someArchetypePropertyAlias, {foo: 1234})}}
  32. console.log(args);
  33. return function ($q, archetypeCacheService) {
  34. var deferred = $q.defer();
  35. archetypeCacheService.getEntityById(args.foo, 'document').then(function(entity) {
  36. console.log("Hello from testEntityPromise2");
  37. console.log(entity);
  38. deferred.resolve(entity.name);
  39. });
  40. return deferred.promise;
  41. }
  42. }

Change the Style of Archetype in the Backoffice

Archetype allows you to do the following to customize the backoffice experience for your editors:

  • Modify the view globally
  • Modify the view per Archetype data type instance
  • Modify the CSS globally
  • Modify the CSS per Archetype data type instance
  • Add a JS script globally
  • Add a class name to an Archetype

Global Changes

To make global changes, simply edit any of these files:

  • Any file located in: ~/App_Plugins/Archetype/views/
  • ~/App_Plugins/Archetype/css/archetype.css

Modifying these files will alter the look and feel of Archetype globally, however this is the same as modifying the core of Archetype and you’ll have to make these changes after each upgrade to the next version of Archetype.

Per Data Type Instance

Archetype will allow you to also change the look and feel on a per data type basis as defined below:

  • You can completely swap out the default view with another one. Navigate to Developer>Data Types and select your Archetype. Update the configuration property View File with a path to your new view file. v7.3+ users will find this under the Custom Style/Script Options. It’s easiest to start with a copy of the ~/App_Plugins/Archetype/Views/archetype.default.html file, make your changes and save it as a new view. Just remember to point your Archetype to the new view.
  • Next you can add CSS and JS conditionally to a page. Since Umbraco is a pretty much a single page app, you can inject a CSS and/or a JS file by simply specifying a path to a CSS or JS file in the Archetype configuration. Again v7.3+ users will find this under the Custom Style/Script Options.
  • Lastly, you can also quickly add a class to an Archetype for styling or JS purposes by specifying the Custom Wrapper Class field in the configuration. This can be used in conjunction with either the JS or CSS file options.

Note that these changes are resistant to upgrades of Archetype and will be kept without any worries unlike the global changes in the previous section.