Copied to clipboard

Flag this post as spam?

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


  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Jan 19, 2016 @ 11:23
    Frans de Jong
    0

    Rte in custom property editor not storing value

    I'm trying to adjust a slider property editor to my taste.

    I wanted to add a rte. The rte renders and it uses the styles. The only thing it doesn't do is store it's value. I don't know where to look and all my googling brought me nowhere...

    Bare with me I'm a beginner in angular and I wanted to start with the property editors by modifying and learning on the way.

    Here is the code:

    view:

    <div id="simple-slider-list-editor" ng-controller="SimpleSliderEditor.controller">
    
        <div ui-sortable="sortableOptions" ng-model="model.value">
    
            <div class="simple-slider-list simple-slider-list-field" ng-class="{'simple-slider-open':selected == slide}" ng-click="select(slide)" ng-repeat="slide in model.value track by $index">
    
    
                <span class="simple-slider-list-number">
                    <span class="slide-name">
                        {{slide.name}}
                    </span>
    
                    <i class="icon right icon-navigation"></i>
                    <i ng-click="remove($index)" class="icon right icon-delete"></i>
                </span>
    
                <div class="slider-left-block">
                    <div class="simple-slider-list-title">
                        <input type="text" placeholder="slide name" ng-model="slide.name" />
                    </div>
    
                    <div class="umb-mediapicker simple-slider-list-field">
                        <ul class="umb-sortable-thumbnails">
                            <li style="width: 120px; height: 100px; overflow: hidden;">
                                <a href ng-click="pick(slide)" class="icon-holder" ng-hide="slide.img">
                                    <i class="icon icon-add large"></i>
                                    <small>Choose...</small>
                                </a>
                                <img ng-src="{{slide.img}}" alt="" ng-show="slide.img">
                                <a href class="picked-image" ng-click="slide.img = null" ng-show="slide.img"><i class="icon icon-delete"></i></a>
                            </li>
                        </ul>
                    </div>
                </div>
    
                <div class="slider-right-block">
    
                    <div ng-controller="SimpleSliderEditor.controller" class="sliderRte">
                        <ng-form>
                            <umb-editor model="rte"></umb-editor>
                        </ng-form>
                    </div>
                </div>
            </div>
            <div class="simple-slider-list-add-row">
                <button ng-click="add()" class="btn">Add slide<i class="icon right icon-add"></i></button>
            </div>
            </div>
    

    controller:

    angular.module("umbraco").controller("SimpleSliderEditor.controller",
        function ($scope, assetsService, $http, dialogService, mediaHelper) {
    
            var defaultItem = { name: "", img: "", rte:"" };
    
            if (!$scope.model.value) {
                $scope.model.value = [];
            }
    
            if ($scope.model.value.length > 0) {
                $scope.selected = $scope.model.value[0];
            }
    
            $scope.select = function (index) {
                $scope.selected = index;
            };
    
            $scope.remove = function ($index) {
                $scope.model.value.splice($index, 1);
            };
    
            $scope.add = function () {
                $scope.model.value.splice($scope.model.value.length + 1, 0, angular.copy(defaultItem));
                $scope.selected = $scope.model.value[$scope.model.value.length-1];
            };
    
            $scope.pick = function (slide) {
                dialogService.mediaPicker({
                    multiPicker: false,
                    callback: function (data) {
                        slide.img = mediaHelper.resolveFile(data, false);
                    }
                });
            };
    
    
            $scope.sortableOptions = {
                handle: ".icon-navigation",
                axis: "y",
                delay: 150,
                distance: 5
            };
    
            $scope.rte = {
                label: 'bodyText',
                description: 'Load some stuff here',
                view: 'rte',
                config: {
                    editor: {
                        toolbar: ["styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "code"],
                        stylesheets: ["/css/rte"],
                        dimensions: { height: 250, width: 550 }
                    }
                }
            };
    
            // Load css asset
            assetsService.loadCss("/App_Plugins/SimpleSliderEditor/SimpleSliderEditor.css");
    
    });
    

    Can someone point me in the right direction?

    Thanks!

  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Jan 19, 2016 @ 13:45
    Frans de Jong
    0

    What I don't get is that there is no connection to the ng-model used by for example the name property.

    I think it has something to do with the rte not being connected to the right model?

  • Ian 178 posts 752 karma points
    Jan 28, 2016 @ 10:18
    Ian
    1

    Hi Frans I should say that I haven't used the rte in my property editors but you could maybe try to debug the issue by adding this to your controller.

    $scope.$on("formSubmitting", function () {
            console.log($scope.model.value);
        });
    

    This should reveal what data is being submitted by angular so you can then see if there is anything amiss between that and what you're expecting

  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Jan 28, 2016 @ 11:00
    Frans de Jong
    0

    Hi Ian,

    Thanks for your reply. I'll give it a try hopefully later this day.

  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Feb 01, 2016 @ 14:36
    Frans de Jong
    0

    Ok, I added the piece of code Ian suggested. I never got the console log message. I pasted it below the $scope.rte part.

    I see the RTE, I can type and style text. When I click save and publish I see nothing wrong but when I reload the page afterward the text in the RTE is gone....

  • Ian 178 posts 752 karma points
    Feb 01, 2016 @ 15:53
    Ian
    1

    I would try to maybe change the console log message to a static string just to see if the submitting function is being called at all i would also put a breakpoint on it in chrome. If that is not running at all it would suggest to me some other js error is being thrown which might account for the other problems you're having.

  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Feb 01, 2016 @ 16:46
    Frans de Jong
    0

    Oh wow...

    Just now I see a error in the console... I didn't see it before becouse it looked like a font error I normaly get with a woff2 file in chrome.

    I get this error in the file tinymce.min.js?umb__rnd=7.3.4.1799828241:11:

    GET http://dev.webwonders.nl/css//css/rte.css.css?1454344706685
    N.initContentBody         @ tinymce.min.js?umb__rnd=7.3.4.1799828241:11
    N.init                                 @ tinymce.min.js?umb__rnd=7.3.4.1799828241:11
    (anonymous function)   @ tinymce.min.js?umb__rnd=7.3.4.1799828241:11
    (anonymous function)   @ tinymce.min.js?umb__rnd=7.3.4.1799828241:5
    a                                         @ tinymce.min.js?umb__rnd=7.3.4.1799828241:2
    h                                         @ tinymce.min.js?umb__rnd=7.3.4.1799828241:5
    (anonymous function)   @ tinymce.min.js?umb__rnd=7.3.4.1799828241:5
    i                                          @ tinymce.min.js?umb__rnd=7.3.4.1799828241:5
    

    Could that be the problem?

    The double css folder and file refernce is weird...

  • Ian 178 posts 752 karma points
    Feb 01, 2016 @ 20:55
    Ian
    1

    an error is being generated, however having tested the code the problem lies with the way the rte editor binds to a model. If you look here some of this is explained http://www.enkelmedia.se/blogg/2013/12/4/umbraco-7-use-the-rich-text-editor-tinymce-in-a-custom-section.aspx.

    At the moment i can confirm that the reason you are getting empty values is because the rte value element of you angular slide model is never getting populated.

    As a test I created an array of rtes (like the $scope.properties example in the link provided) with the 'value' property populated with the 'rte' property value from each slide item in your model.value array. The problem with this approach is that you then need to keep this in sync with your model value array adding and removing from the rtes array each time to add or remove a slide. This is easy enough but then you have the sortable element for your slides which, for everything to work would also need to re sort the list of rtes. Added to this when you re-sort the editors seem to become disabled somehow, and as i haven't used the rte in this way I wouldn't know the fix.

    So really there are a few issues before getting something that works

  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Feb 02, 2016 @ 07:07
    Frans de Jong
    0

    Thanks a lot Ian,

    If we could store the rte's in a array with a key value pair it would make life a lot easier right?

    If we were to store a hidden Id with a slide and use that Id as a key for a rte, we would be able to connect the 2. We than have to catch the sort event and sort the rte array also.

    A quick fix would be to get rid of the sort option to make life a lot easier right?

    I'm new to angular and this a whole new game compared to Jquery and razor...

    Thanks again!!

  • Ian 178 posts 752 karma points
    Feb 02, 2016 @ 09:57
    Ian
    1

    I would look at the archetype package and see how they do things as one of its features is repeatable fields a bit like you are doing in your custom editor. I'm not saying this is code you can just drop straight in but this is some of their code in archetype.js just for you to get some ideas.

    $scope.sortableOptions = {
        axis: 'y',
        cursor: "move",
        handle: ".handle",
        start: function(ev, ui) {
            draggedRteSettings = {};
            ui.item.parent().find('.mceNoEditor').each(function () {
                // remove all RTEs in the dragged row and save their settings
                var id = $(this).attr('id');
                draggedRteSettings[id] = _.findWhere(tinyMCE.editors, { id: id }).settings;
                tinyMCE.execCommand('mceRemoveEditor', false, id);
            });
        },
        update: function (ev, ui) {
            $scope.setDirty();
        },
        stop: function (ev, ui) {
            ui.item.parent().find('.mceNoEditor').each(function () {
                var id = $(this).attr('id');
                draggedRteSettings[id] = draggedRteSettings[id] || _.findWhere(tinyMCE.editors, { id: id }).settings;
                tinyMCE.execCommand('mceRemoveEditor', false, id);
                tinyMCE.init(draggedRteSettings[id]);
            });
        }
    };
    
  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Feb 02, 2016 @ 10:06
    Frans de Jong
    0

    Thanks for the effort Ian!

    I hope I can look into it tomorow. This has become a after hours issue for me as I can't stand it I can't figure this out...

  • Avatar 15 posts 92 karma points
    Oct 03, 2016 @ 01:41
    Avatar
    1

    I haven't tested the ui-sorting, I'm sure there will be some extra tweaking for that.

    The RTE configuration is being defined on the global scope for your controller, but the umb-editor is being used inside of ng-repeat, which has it's own scope. The RTE still renders because angular knows to check for properties on the scope recursively through parent scopes, but can't bind the rte's value to each item in your model.value.

    The simplest way to resolve this is to add the rte to each item you add to model.value. Try making your $scope.defaultItem as follows:

    $scope.defaultItem = { 
        name: "",
        img: "",
        rte: {
            label: 'bodyText',
            description: 'Load some stuff here',
            view: 'rte',
            config: {
                editor: {
                    toolbar: ["styleselect", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "code"],
                    //stylesheets: ["/css/rte"],
                    dimensions: { height: 250, width: 550 }
                }
            },
            value: "<p>Enter your slide content here</p>"
         }
    };
    

    In your editor, you will want to change the model of umb-editor to slide.rte

    <umb-editor model="slide.rte"></umb-editor>
    

    With the above, your rte configuration and it's value is part of each slide item, and the value will be populated with "Enter your slide content here" whenever you add a new slide.

    When the rte's content is edited, the value is stored right back to it, so now it should save.

  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Nov 10, 2016 @ 14:52
    Frans de Jong
    100

    Hi Rami,

    Sorry for the late reply! Thanks for looking in to it.

    Meanwhile I've diverted NestedContent for sliders. Absolutely no problem with all the propertyeditors.

    Frans

  • Avatar 15 posts 92 karma points
    Nov 10, 2016 @ 14:55
    Avatar
    1

    Well that sounds useful! Please share and make some of our lives easier :)

  • Frans de Jong 548 posts 1840 karma points MVP 3x c-trib
    Nov 10, 2016 @ 15:06
    Frans de Jong
    0

    First install NestedContent (package or nuget)

    After that you create I create a documenttype called -slider (I use minus as a prefix for my nestedcontent doctypes) with in my case the following properties:

    slideTitle - textstring slideImage - Media Picker slideText - RTE

    After this step I create a Data type using the nested content propertyeditor. In this case called Homepage Slider.

    As the documenttype I select -Slider, the tab is de name of the tab you want to use in -Slider. In Name Template i put {{slideTitle}}.

    The only thing left is adding a partial view to your template looking something like this:

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
    @{
        List<IPublishedContent> slides = new List<IPublishedContent>();
        int slidesCount = 0;
        if (CurrentPage.HasProperty("slides") && CurrentPage.HasValue("slides")) {
            slides = CurrentPage.GetPropertyValue<List<IPublishedContent>>("slides");
            slidesCount = slides.Count();
        }
    }
    
    @if (slidesCount > 0) { 
        <div id="myCarousel" class="carousel slide" data-ride="carousel">
            <!-- Indicators -->
            <ol class="carousel-indicators">
                @for (int i = 0; i < slidesCount; i++)
                {
                    <li data-target="#myCarousel" data-slide-to="@i" class="@(i==0? "active" : null)"></li>
                }
            </ol>
    
            <!-- Wrapper for slides -->
            <div class="carousel-inner" role="listbox">
    
                @foreach (IPublishedContent slide in slides)
                {
                    bool isFirstSlide = slide == slides.First();
                    @buildSlide(slide, isFirstSlide)
                }
    
            </div>
    
            <!-- Left and right controls -->
            <a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
                <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
                <span class="sr-only">Previous</span>
            </a>
            <a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
                <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                <span class="sr-only">Next</span>
            </a>
        </div>
    }
    
    @helper buildSlide(IPublishedContent slide, bool isFirstSlide)
    {
        IPublishedContent img = Umbraco.Media(slide.GetPropertyValue("slideImage"));
        <div class="item @(isFirstSlide ? "active": null)" style="background-image: url(@img.Url);">
            <img src="@img.Url" alt="@img.Name" class="imgFullWidth invisible">
            @if (slide.HasValue("slideText"))
            {
                <div class="slideContent container"  style="@(slide.HasValue("textBackgroundColor") ? "background-color: " + @slide.GetPropertyValue("textBackgroundColor") + ";": "")" >
                    <div class="slideContentInner">
                        @slide.GetPropertyValue("slideText")
                    </div>
                </div>
            }
        </div>
    }
    

    The end result looks something like this:

    enter image description here

  • Jonathan Roberts 409 posts 1063 karma points
    Jul 26, 2017 @ 09:02
    Jonathan Roberts
    0

    Hi,

    I get $scope.setDirty is not a function - have I missed something?

  • Jakob Kristensen 36 posts 169 karma points
    Dec 18, 2017 @ 14:44
    Jakob Kristensen
    0

    Could we maybe soon have some documentation for custom sections its getting abit annoying having to hack everything together rather than using the frameworks..

Please Sign in or register to post replies

Write your reply to:

Draft