November Happy Hour will be moved to Thursday December 5th.

Custom Media Component With 'Create New' Functionality Breaks After EPiServer 11 Upgrade

Vote:
 

Hi,

 

I am in the process of updating an EPiServer site from version 9.6.1 to 11.10.0.

In the process I have come across a problem which I cannot resolve.

 

The site have a custom ‘video component’ which allows the editors to manage ‘video assets’ in the same way as they manage ‘Blocks’ and ‘Media’.

The component is build using the build-in Component attribute and a  MediaRepositoryDescriptor and 3 custom JS files.

 

The problem:

There is a 'Create new item' button, just like when creating a new block or media.

Clicking the button is supposed to navigate the editor to a page, where they can create the ‘video asset’ - Just as creating a new block would.

The result of clicking the button is an empty page, and no errors in the Chrome Debugger Tools.

 

I have done the following, based on the breaking changes that I am aware of:

  • Changed dot notation to “/” notation.
  • Replaced epi-cms/widget/HierarchicalList with epi-cms/asset/HierarchicalList
  • Replaced epi-cms/widget/viewmodel/HierarchicalListViewModel with epi-cms/asset/view-model/HierarchicalListViewModel
  • Added this.noDataMessages = ...; & this.noDataMessage = ...; in VideoAssetViewModel.js (see below)
  • Added noDataMessages: ... in VideoAsset.js (see below)

These are the files used: (created in the Alloy demo project, so paths have the namespace "alloy".)

The component:

    [Component]
    public class VideoAssetComponent : ComponentDefinitionBase
    {
        public VideoAssetComponent()
            : base("epi-cms/component/SharedBlocks")
        {
            PlugInAreas = new[] { PlugInArea.AssetsDefaultGroup }; // Which area this component be rendered in.
            Categories = new[] { "content" }; // Where to display the widget (cms / commerce / find / content / dashboard ).
            WidgetType = "alloy/VideoAsset"; // Tell EPiServer where to find the custom JS file that will define which view should be loaded.
            SortOrder = 1100;
            Description = "Video asset to store video content type";
            Title = "Video Asset";
            Settings.Add(new Setting("repositoryKey", VideoAssetDescriptor.RepositoryKey));
        }
    }

The Descriptor:

    [ServiceConfiguration(typeof(IContentRepositoryDescriptor))]
    public class VideoAssetDescriptor : MediaRepositoryDescriptor
    {
        public new static string RepositoryKey => "video";

        public override string Key => RepositoryKey;

        public override string Name => "video";

        public override IEnumerable ContainedTypes => new[]
        {
            typeof(ContentFolder),
            typeof(Video)
        };

        public override IEnumerable CreatableTypes => new[] { typeof(Video) };

        public override IEnumerable Roots
        {
            get
            {
                var roots = new List { SiteDefinition.Current.GlobalAssetsRoot };
                if (SiteDefinition.Current.GlobalAssetsRoot != SiteDefinition.Current.SiteAssetsRoot)
                {
                    roots.Add(SiteDefinition.Current.SiteAssetsRoot);
                }
                return roots;
            }
        }

        public override IEnumerable MainNavigationTypes => new[]
        {
            typeof(ContentFolder)
        };
    }

The main dojo JS file:

define([
        "dojo/_base/declare",
        "alloy/VideoAssetViewModel",
        "epi-cms/asset/HierarchicalList",
        "dijit/_WidgetBase",
        "epi/i18n!epi/cms/nls/episerver.cms.components.media" // Location of EPiServers translation file with dot-notation for XML structure.
    ],
    // Parameters must match import statements above.
    function (declare, VideoWidgetViewModel, HierarchicalList, _WidgetBase, resources) {
        return declare("alloy/VideoAsset",
            [HierarchicalList],
            {
                res: resources,
                createContentText: "Click to create item",
                enableDndFileDropZone: false,
                showCreateContentArea: true,
                showThumbnail: true,
                modelClassName: VideoWidgetViewModel,
                noDataMessage: resources.nocontent,
                noDataMessages: resources.nodatamessages,
                hierarchicalListClass: "epi-mediaList",

                _onCreateAreaClick: function () {
                    // summary:
                    //      A callback function which is executed when the create area is clicked.
                    // tags:
                    //      protected
                    this.inherited(arguments);
                    this.model._commandRegistry.newVideo.command.execute();
                }
            });
    });

The view-model dojo JS file:

define("alloy/VideoAssetViewModel",
    [
        "dojo/_base/declare",
        "dojo/_base/lang",
        "epi-cms/asset/view-model/HierarchicalListViewModel",
        "alloy/NewVideoCommand",
        "epi/i18n!epi/cms/nls/episerver.cms.components.media"
    ],
    function(
        declare,
        lang,
        HierarchicalListViewModel,
        NewVideoCommand,
        resources
    ) {

        return declare([HierarchicalListViewModel],
            {
                // summary:
                //      Handles search and tree to list browsing widgets.
                // tags:
                //      internal
                _getTypesToCreate: function () {
                    return [];
                },
                _setupCommands: function () {
                    // summary:
                    //      Creates and registers the commands used.
                    // tags:
                    //      protected
                    //
                    var tempCreatableTypes = this.creatableTypes;
                    //assign creatableTypes to null temporarily to avoid the automatically generated New Item option in the context menu
                    this.creatableTypes = null;
                    this.inherited(arguments);
                    this.creatableTypes = tempCreatableTypes;
                    this.noDataMessages = resources.nodatamessages;
                    this.noDataMessage = resources.nocontent;
                    var customCommands = {
                        newVideo: {
                            command: new NewVideoCommand(lang.mixin({
                                iconClass: "epi-iconPlus",
                                label: "New video",
                                canExecute: true, //XYI: to enable the button
                                viewModel: this,
                                contentType: this.creatableTypes[0],
                                createAsLocalAsset: false,
                                autoPublish: true
                            }))
                        },
                        newVideoContext: {
                            command: new NewVideoCommand(lang.mixin({
                                category: "context",
                                iconClass: "epi-iconPlus",
                                label: "New video",
                                viewModel: this,
                                contentType: this.creatableTypes[0],
                                createAsLocalAsset: false,
                                autoPublish: true
                            })),
                            isAvailable: this.treeStoreModel.root.name === "ROOT" | this.treeStoreModel.root.name === "TREE",
                            order: 2
                        }
                    };
                    this._commandRegistry = lang.mixin(this._commandRegistry, customCommands);
                    this.pseudoContextualCommands.push(this._commandRegistry.newVideo.command);
                    this.pseudoContextualCommands.push(this._commandRegistry.newVideoContext.command);
                },
                _updateTreeContextCommandModels: function (model) {
                    // summary:
                    //      Update model of commands in case selected content is folder
                    // tags:
                    //      private
                    this.inherited(arguments);
                    this._commandRegistry.newVideo.command.set("model", model);
                    this._commandRegistry.newVideoContext.command.set("model", model);
                }
            });

    });

The commands dojo JS file:

define("alloy/NewVideoCommand",
    [
        "dojo/_base/declare",
        "dojo/topic",
        "epi/shell/TypeDescriptorManager",
        "epi-cms/command/NewContent"
    ],
    function(declare, topic, TypeDescriptorManager, NewContentCommand) {
        
        return declare([NewContentCommand],
            {
                _execute: function () {
                    // summary:
                    //      Executes this command; publishes a change view request to change to the create content view.
                    // tags:
                    //      protected
                    topic.publish("/epi/shell/action/changeview",
                        "epi-cms/contentediting/CreateContent",
                        null,
                        {
                            requestedType: this.contentType,
                            editAllPropertiesOnCreate: this.editAllPropertiesOnCreate,
                            parent: this.model,
                            autoPublish: this.autoPublish,
                            createAsLocalAsset: this.createAsLocalAsset,
                            view: TypeDescriptorManager.getValue(this.contentType, "createView"),
                            addToDestination: {
                                save: function() {
                                }
                            }
                        });
                }
            });
    });

Is there anyone who can come with ideas how to further debug this problem?

Thanks in advance

/Mads

#197682
Oct 10, 2018 14:24
Vote:
 

Hello Mads,

You are missing this method in your VideoAssetViewModel:

_selectedTreeItemsSetter: function (selectedItems) {
	this._commandRegistry.newVideo.command.set("model", selectedItems);

	this.inherited(arguments);
}

After adding it you should be able to add new videos:

#198283
Oct 24, 2018 14:42
Vote:
 

Hi Bartosz, 

Thank you for the support.

It resolved our issues, and the editors can once again create Video Assets :)

#198434
Oct 29, 2018 8:44
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.