Calling all developers! We invite you to provide your input on Feature Experimentation by completing this brief survey.

 

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.