Image Selector on Custom Controls - General Discussions - General Discussions - Progress Community
 General Discussions

Image Selector on Custom Controls

  • Image Selector on Custom Controls
  • Hey Telerik Team,

    In following along with various posts in how to implement page selectors in custom control templates, I was wondering how you might go about implementing an image selector in a custom control template - choosing an image from the libraries as you see in the regular Sitefinity Image widget.

    Can you point me to some documentation or code example that would illustrate that?  I apologize if this has been answered previously.  I just can't seem to find that in a forum search.

    Thanks

    - Wiliam
  • Hello WilliamCooper,

    You could use MediaContentSelectorView control to achieve the required functionality. Here is an example how to declare it:

    <%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Modules.Libraries.Web.UI.Designers" TagPrefix="sf" %>
    <sf:MediaContentSelectorView
        id="selectorView"
        runat="server"
        ContentType="Telerik.Sitefinity.Libraries.Model.Image"
        ParentType="Telerik.Sitefinity.Libraries.Model.Album"
        LibraryBinderServiceUrl="~/Sitefinity/Services/Content/AlbumService.svc/"
        MediaContentBinderServiceUrl="~/Sitefinity/Services/Content/ImageService.svc/"
        MediaContentItemsListDescriptionTemplate="Telerik.Sitefinity.Resources.Templates.Designers.Libraries.Images.ImageItemDescriptionTemplate.htm"
        DisplayResizingOptionsControl="false"
        ShowOpenOriginalSizeCheckBox="false">
    </sf:MediaContentSelectorView>

    Let us know if this helps.

    Kind regards,
    Pepi
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  • Hi Pepi,

    Thanks for that nice code snippet, those help.  I'll try to implement it tomorrow.

    I'm assuming that registering that designer in the .cs file is similar to how you'd register the page selector?  If not, can you give me an idea of what the .cs file and the .js file would look like in terms of the custom control designer?

    Thanks much.  I'll post again when I've had a chance to test it out.

    Great work on the final release.

    - William
  • Hello William,

    Please take a look at How to create a custom widget.  If there are any questions, please update the post with them.

    Best wishes,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  • Hi Ivan,

    I guess my question (and I've done a number of custom widgets now in my testing) is how to get and set the value of the Media Selector.  With the Page Selector, there was a great deal of component registering and javascript code that supported passing values back and forth.

    So the big question is, what goes in the refreshUI and applyChanges blocks of the prototype to support getting a usuable value from the Media Selector to pass?  And if necessary, what would go in the supporting .cs file in terms of ScriptDescriptors to register the Media Selector component?

    Thanks!

    - William

  • Hello William,

    refreshUI()
    This method is called, when you need to refresh or update the user interface of your designer with the new data. Sitefinity automatically calls this method every time it needs to (for example, user switches to advanced mode and changes some properties in the property grid, then switches back to the simple mode or designer – this method will be called so that you can update the user interface of your designer with the changes that have been made in the advanced mode. Generally you can think of this method as “from data to user interface”.

    - applyChanges()
    This method is called, when Sitefinity needs to get the properties from your designer. For example, let’s say that user clicks the “Done” button in the designer. In that case Sitefinity needs to get all the properties from your designer and persist them so that it can render the widget properly. Generally, you can think of this method as “from user interface to data”.

    Kind regards,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  • Hey Ivan,

    I actually understand how the prototype methods works, as I've done several custom controls by now.  My question was about specifics.  I can't quite figure out what the actual code would be to get the value from the Media Selector mentioned by Pepi and pass it a value in.  Can you provide any specifics for this case?

    For instance, looking at the value in "selectorView" returns undefined on submit.  Obviously that's not the correct place to look for the value of the image selected.  So where would that be?

    A quick code snippet would be fantastic if possible.

    Thanks

    - William
  • Hello William,

    Inside Initialize of your javascript you can create a delegate and subscribe for onItemSelectCommand

    this._itemSelectDelegate = Function.createDelegate(this, this._itemSelect); this.add_onItemSelectCommand(this._itemSelectDelegate);

    and get the selected item


        _itemSelect: function (sender, args)
            var dataItem = args.get_dataItem();
        ,

        add_onItemSelectCommand: function (delegate)
            this.get_events().addHandler('onItemSelectCommand', delegate);
        ,

    All the best,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  • Hello,

    I need this image selector too but in a custom module I develop.

    Is there a way to add it to the insert form definitions using a definition element?

    Can you provide me a short sample to do this?

    Thanks

    Jocelyn
  • Hey Ivan,

    I think I'm still missing either some pieces to this, or some understanding.  I'm going to share the code I have so far and maybe you can tell me what is missing in terms of capturing information about the image selected when somebody hits "save".  Basically, I need to capture information about the image selected so that I can pass it back to the control that calls it, and obviously pass information back from the control to the selector to pre-select images.

    Since in advanced cases, one might like to have multiple image selectors, I'd need that information pass back from that specific selector so that I could potentially add a second to the control.  In other words, the data needs to come from "selectorView" specifically.

    ImageControlDesignerTemplate.ascx
    <%@ Control Language="C#"%>
    <%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI.Fields" TagPrefix="sfFields" %>
    <%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
    <%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sitefinity" %>
    <%@ Register Assembly="Telerik.Sitefinity" TagPrefix="designers" Namespace="Telerik.Sitefinity.Web.UI.ControlDesign" %>
    <%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Modules.Libraries.Web.UI.Designers" TagPrefix="sf" %>
    <sf:MediaContentSelectorView
        id="selectorView"
        runat="server"
        ContentType="Telerik.Sitefinity.Libraries.Model.Image"
        ParentType="Telerik.Sitefinity.Libraries.Model.Album"
        LibraryBinderServiceUrl="~/Sitefinity/Services/Content/AlbumService.svc/"
        MediaContentBinderServiceUrl="~/Sitefinity/Services/Content/ImageService.svc/"
        MediaContentItemsListDescriptionTemplate="Telerik.Sitefinity.Resources.Templates.Designers.Libraries.Images.ImageItemDescriptionTemplate.htm"
        DisplayResizingOptionsControl="false"
        ShowOpenOriginalSizeCheckBox="false">
    </sf:MediaContentSelectorView>

    ImageControlDesigner.js
    Type.registerNamespace("TestAppCustomControls");
     
    TestAppCustomControls.ImageControlDesigner = function (element)
        TestAppCustomControls.ImageControlDesigner.initializeBase(this, [element]);
    TestAppCustomControls.ImageControlDesigner.prototype =
        initialize: function ()
            TestAppCustomControls.ImageControlDesigner.callBaseMethod(this, 'initialize');
     
            // Specific to image selector
            this._itemSelectDelegate = Function.createDelegate(this, this._itemSelect);
            this.add_onItemSelectCommand(this._itemSelectDelegate);
        ,
        dispose: function ()
            TestAppCustomControls.ImageControlDesigner.callBaseMethod(this, 'dispose');
        ,
        refreshUI: function ()
            var data = this._propertyEditor.get_control();
            // Something goes here to set the image selector 'selectorView' to the selected image
        ,
        applyChanges: function ()
            var controlData = this._propertyEditor.get_control();
            // Something goes here to save the image selected from 'selectorView' and pass it to the control.
        ,
        _itemSelect: function (sender, args)
            var dataItem = args.get_dataItem();
        ,
        add_onItemSelectCommand: function (delegate)
            this.get_events().addHandler('onItemSelectCommand', delegate);
        
    TestAppCustomControls.ImageControlDesigner.registerClass('TestAppCustomControls.ImageControlDesigner', Telerik.Sitefinity.Web.UI.ControlDesign.ControlDesignerBase);
    if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

    ImageControlDesigner.cs
    using System.Collections.Generic;
    using System.Web.UI;
    using System.Linq;
    using Telerik.Sitefinity.Web.UI.ControlDesign;
    using Telerik.Web.UI;
    using Telerik.Sitefinity.Web.UI.Fields;
    using System.Web.UI.WebControls;
    using Telerik.Sitefinity.Modules.Libraries.Web.UI.Designers;
     
    namespace TestAppCustomControls
     
        public class ImageControlDesigner : ControlDesignerBase
        
            protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
            
                //throw new System.NotImplementedException();
                base.DesignerMode = ControlDesignerModes.Simple;
            
     
            protected override string LayoutTemplateName
            
                get
                
                    return "TestAppCustomControls.Resources.ImageControlDesignerTemplate.ascx";
                
            
     
            public override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
            
                var scriptDescriptors = new List<ScriptDescriptor>(base.GetScriptDescriptors());
                var desc = (ScriptControlDescriptor)scriptDescriptors.Last();
                return scriptDescriptors.ToArray();
            
     
            public override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
            
                var res = new List<ScriptReference>(base.GetScriptReferences());
                var assemblyName = this.GetType().Assembly.GetName().ToString();
                res.Add(new ScriptReference("TestAppCustomControls.Resources.ImageControlDesigner.js", assemblyName));
                return res.ToArray();
            
     
            /// <summary>
            /// Gets a reference to the media selector
            /// </summary>
            protected MediaContentSelectorView MediaSelector
            
                get
                
                    return Container.GetControl<MediaContentSelectorView>("selectorView", true);
                
            
        

    Thanks!

    - William
  • Hello William,

    Inside the control designer you have to add reference to MediaContentSelectorView and then send  its client ID to the client side component.

    public override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
       
           var scriptDescriptors = new List<ScriptDescriptor>(base.GetScriptDescriptors());
           var desc = (ScriptControlDescriptor)scriptDescriptors.Last();
           desc.AddComponentProperty("selectorView", SelectorView.ClientID);
           return scriptDescriptors.ToArray();
       
     
       /// <summary>
       /// Gets a collection of <see cref="T:System.Web.UI.ScriptReference"/> objects that define script resources that the control requires.
       /// </summary>
       /// <returns>
       /// An <see cref="T:System.Collections.IEnumerable"/> collection of <see cref="T:System.Web.UI.ScriptReference"/> objects.
       /// </returns>
       public override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
       
           var res = new List<ScriptReference>(base.GetScriptReferences());
           var assemblyName = this.GetType().Assembly.GetName().ToString();
           res.Add(new ScriptReference(designerScriptName, assemblyName));
           return res.ToArray();
       
     
     
       protected virtual MediaContentSelectorView SelectorView
       
           get
           
               return this.Container.GetControl<MediaContentSelectorView>("selectorView", true);
           
       

    Then you can access the MediaContentSelectorView object and listen to the click event

    Telerik.Sitefinity.Samples.SimpleViewCustomDesigner = function (element)
     
        // element
        this._selectorView = null;
        this._itemSelectDelegate = null;
        Telerik.Sitefinity.Samples.SimpleViewCustomDesigner.initializeBase(this, [element]);
     
     
    Telerik.Sitefinity.Samples.SimpleViewCustomDesigner.prototype =
     
        initialize: function ()
            Telerik.Sitefinity.Samples.SimpleViewCustomDesigner.callBaseMethod(this, 'initialize');
            this._itemSelectDelegate = Function.createDelegate(this, this._itemSelect);
            this._selectorView.add_onItemSelectCommand(this._itemSelectDelegate);
     
        ,
     
        dispose: function ()
            Telerik.Sitefinity.Samples.SimpleViewCustomDesigner.callBaseMethod(this, 'dispose');
     
            if (this._selectorView)
                this._selectorView.add_onItemSelectCommand(this._itemSelectDelegate);
            
     
        ,
     
     
        get_selectorView: function ()
            return this._selectorView;
        ,
        set_selectorView: function (value)
            this._selectorView = value;
        ,
     
            _itemSelect: function (sender, args)
            var dataItem = args.get_dataItem();
        ,


    Regards,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  • Ivan,

    Yes, I was indeed missing a piece of this.  Mainly, I'd forgotten to add the SelectorView into the GetScriptDescriptors.

    This works like a charm now, thanks.

    One extra question, which I don't necessarily need for this, but which would make the solution complete.  Can you show me how you'd pre-select an image based on a GUID passed in?  In other words, I'd love it if the image you'd previously selected was pre-selected when you went to edit later.

    I'm assuming that's another handler, but I'm not sure which handlers are involved with the Media Selector.

    Any ideas?

    Thanks

    - William

  • Hi William,

    You can use css , but you should pass the value back to itemSelected. You can keep the key in gloabal variable. The code should something like this.


       _itemSelected: function (sender, args)
            var dataItem = args.get_dataItem();
            // or you can try getting the image key from the args
            this._selectedImageKey = args.get_key();
            var selectedElement = args.get_itemElement();
            this._highlightSelectedImage(selectedElement);

        ,

       
        _highlightSelectedImage: function (selectedElement)
            if (this.selectedImageElement)
                if (this.selectedImageElement != selectedElement)
                    $(this.selectedImageElement).find(".imgSelect").removeClass("sfSelImgBorder");
                    $(this.selectedImageElement).removeClass("sfSel");
                else
                    $(this.selectedImageElement).addClass("sfSel");
               
           

            if (selectedElement)
                this.selectedImageElement = selectedElement;
                $(selectedElement).find(".imgSelect").addClass("sfSelImgBorder");
           

        ,

    Regards,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  • Hi Ivan,

    I've had a go at getting an image selector working as in the code examples above.  I have some textboxes that I'm using to set string values in my control from the designer (which all work fine),  I can see and select images, however I also want to set the url of the selected image from the custom designer into a string value on the control and I can't work out how to do this.  Could you provide an example of how I can achieve this?

    In the designer.js I have the following

        get_widthTxtControl: function ()
            return this._widthTxtControl;
        ,
        set_widthTxtControl: function (value)
            this._widthTxtControl = value;
        ,

        refreshUI: function ()
            var data = this.get_controlData();

            $("#" + this._widthTxtControl.id).val(data.Width);
        ,
        
        applyChanges: function ()
            var data = this.get_controlData();

            data.Width = $("#" + this._widthTxtControl.id).val();
       
        
    I've tried adding something like but no luck

        var imageUrl = args.get_dataItem().MediaUrl;
        this.set_imageSelectorView(imageUrl);
        
    Once I get that working I'd also like to add another MediaContentSelectorView for selecting documents, so I'm hoping this will be a similar process.

    Thanks in advance
    Mark