Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Martin Rud 232 posts 902 karma points c-trib
    Nov 09, 2023 @ 21:34
    Martin Rud
    0

    How to create a property editor that parses XML from another property on the same document?

    Hi forum,

    On a document type I have a field "apiImages" that contains XML like this:

      <photos>
        <photo>
          <order>5</order>
          <url>https://www.domain.com/public/hhhphotos/653/653-21.jpg</url>;
          <filedate>2023-02-21 18:33:37</filedate>
          <descuk>Living and dining room</descuk>
        </photo>
        <photo>
          <order>10</order>
          <url>https://www.domain.com/public/hhhphotos/653/653-17.jpg</url>;
          <filedate>2023-02-21 18:33:32</filedate>
          <descuk>Living room</descuk>
        </photo>
    ...
        </photos>
    

    I want to create a property editor so I can have a dropdown property on the same document type. The dropdown should list the image urls, so the editor can pick an image (in case the editor wants a specific image to be the cover image for the product).

    I have created a Hello world property editor based on https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-property-editor, and I thought I would be able to google how to make it grab the XML from the apiImages property. The rest (creating the dropdown by parsing the XML) I think I will be able to manage myself, but the grab-XML-task I can't google and I can't seem to figure out myself (or with Chat GPT 😁).

    Can anyone lead me in the right direction? I guess it starts in the XmlPicker.cs file.

    Here is my code:

    App_Code\XmlPicker.cs

    using Umbraco.Cms.Core.IO;
    
    namespace Umbraco.Cms.Core.PropertyEditors
    {
        [DataEditor(
            alias: "Xml Picker",   // Must be unique
            name: "Xml Picker",
            view: "~/App_Plugins/XmlPicker/picker.html",
            Group = "Common",
            Icon = "icon-list")]
        public class XmlPicker : DataEditor
        {
            public XmlPicker(IDataValueEditorFactory dataValueEditorFactory)
                : base(dataValueEditorFactory)
            {            
    
            }
        }
    }
    

    App_Plugins\XmlPicker\picker.html

    <div class="image-picker" ng-controller="ImagePickerPluginController">
        <!-- TODO! -->
    </div>
    

    App_Plugins\XmlPicker\picker.controller.js

    angular.module("umbraco").controller("ImagePickerPluginController", function ($scope, entityResource) {
        // TODO!
    });
    
  • james whittington 18 posts 116 karma points c-trib
    Nov 10, 2023 @ 08:26
    james whittington
    0

    I believe this is a way to access the model of the entire page, but it might be better to reach for the amazing contentment package in this situation:

    It looks like you would be able to use one of these two pickers to build out your idea: https://github.com/leekelleher/umbraco-contentment/blob/develop/docs/editors/data-list.md or https://github.com/leekelleher/umbraco-contentment/blob/develop/docs/editors/data-picker.md

    depending where this xml came from, you might even find that you can actually build a custom picker that fetches it from the origional source instead of saving it on the document type.

    On final thing to note, is that if your custom picker needs to access a field on the current page, the page will need to be saved with data in that field before you can access it.

  • Martin Rud 232 posts 902 karma points c-trib
    Nov 10, 2023 @ 08:58
    Martin Rud
    0

    Thanks - I will look into the two pickers.

    I still also would like to know how to retrieve data in my own custom property editor. The XML data is already saved on the node before I will try to retrieve it.

  • james whittington 18 posts 116 karma points c-trib
    Nov 12, 2023 @ 21:09
    james whittington
    0

    I think you could use the https://apidocs.umbraco.com/v12/ui/#/api/umbraco.services.editorState service to get access to your current page.

    Once you have that, I guess you can parse the xml somehow in your own property editor and extract the data you need.

  • Martin Rud 232 posts 902 karma points c-trib
    Nov 14, 2023 @ 14:01
    Martin Rud
    0

    Thanks - that sent me in the right direction:

    App_Plugins\MartinRud.XmlPicker\picker.controller.js

    angular.module("umbraco").controller("ImagePickerPluginController", function ($scope, editorState, contentResource) {
        console.log(editorState.current.variants[0].tabs);
    
        var hrPhotosAlias = "hr_photos";
        var primaryImageAlias = "primaryImage";
    
        // Find the indices of properties
        var hrPhotosIndex = -1;
        var primaryImageIndex = -1;
    
        for (var i = 0; i < editorState.current.variants[0].tabs[0].properties.length; i++) {
            var property = editorState.current.variants[0].tabs[0].properties[i];
            if (property.alias === hrPhotosAlias) {
                hrPhotosIndex = i;
            } else if (property.alias === primaryImageAlias) {
                primaryImageIndex = i;
            }
    
            // Exit the loop early if both properties are found
            if (hrPhotosIndex !== -1 && primaryImageIndex !== -1) {
                break;
            }
        }
        console.log(hrPhotosIndex, primaryImageIndex)
        if (hrPhotosIndex !== -1 && primaryImageIndex !== -1) {
            // Get the property value by alias
            var hrPhotosXml = editorState.current.variants[0].tabs[0].properties[hrPhotosIndex].value;
    
            // Create an empty array to store the image data
            $scope.imageOptions = [];
    
            // Parse the XML data
            var parser = new DOMParser();
            var xmlDoc = parser.parseFromString(hrPhotosXml, "text/xml");
            var photoNodes = xmlDoc.getElementsByTagName("photo");
    
            // Loop through the <photo> elements and add them as options
            for (var j = 0; j < photoNodes.length; j++) {
                var photo = photoNodes[j];
                var url = photo.querySelector("url").textContent;
                var descuk = photo.querySelector("descuk").textContent;
    
                var filename = url.substring(url.lastIndexOf('/') + 1);
                var label = descuk + " (" + filename + ")";
    
                $scope.imageOptions.push({ value: url, label: label });
            }
    
    
            //$scope.selectedImage = hrPhotosXml;
            $scope.$watch("selectedImage", function (newValue, oldValue) {
                editorState.current.variants[0].tabs[0].properties[primaryImageIndex].value = newValue;
            });
        }
    });
    

    App_Plugins\MartinRud.XmlPicker\picker.html

    <div class="image-picker" ng-controller="ImagePickerPluginController">
        <select ng-model="selectedImage"
            ng-options="image.value as image.label for image in imageOptions | orderBy:'label'">
            <option value="">Select an image</option>
        </select>
    </div>
    

    But how do I save the choice when editor hits Save og Publish?

    Right now I transfer the chosen value to another property ("primaryImageAlias" of type textstring). Ideally I would like the choice to be saved to the property itself, but that's not important now.

Please Sign in or register to post replies

Write your reply to:

Draft