Copied to clipboard

Flag this post as spam?

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


  • yogesh pathak 136 posts 221 karma points
    Jul 30, 2015 @ 04:22
    yogesh pathak
    0

    Index complex data of grid editor

    Hi All, I am trying to index data of Grid editor in examine , my problem is i have complex data stored in my grid editor let say array of arrays , so how can i achieve this?. do i have just to make a model smiler to my grid data or anything addition i need to do?

    Yogesh

  • yogesh pathak 136 posts 221 karma points
    Jul 30, 2015 @ 12:13
    yogesh pathak
    0

    Hi Anders, can you provide me some pointers to achieve this? because if it not possible with the solution we have discussed i need to look for other options and i am running short of time :(

    Yogesh

  • Anders Bjerner 487 posts 2990 karma points MVP 8x admin c-trib
    Jul 30, 2015 @ 12:18
    Anders Bjerner
    0

    It is possible. I just haven't had the time to answer yet. I will look at it in a few hours when I'm back at my computer ;)

    Anyways, can you provide some further information about the editor? Eg. an example of the JSON your editor is generating? That would help me give a better answer.

  • yogesh pathak 136 posts 221 karma points
    Jul 30, 2015 @ 14:39
    yogesh pathak
    0

    Hi Anders , my json is being generated is something like bellow

    { "name": "1 column layout", "sections": [ { "grid": 12, "rows": [ { "name": "Row", "areas": [ { "grid": 12, "allowAll": false, "allowed": [ "paragraphGroup" ], "controls": [ { "value": { "focalPoint": { "left": 0.5, "top": 0.5 }, "id": 3071, "image": "/media/1005/why-automate-testing.jpg", "imageRowId": "pGropEditor2" }, "editor": { "name": "Paragraph Group", "alias": "paragraphGroup", "view": "/app_plugins/ParagraphGroupEditor/ParagraphGroup.html", "render": null, "icon": "icon-movie-alt", "config": {} }, "id": 4, "tabelsData": [ { "heading": "tab1", "imagePath": "/media/1010/test.png", "id": "pGropEditor1", "content": "yogesh", "revertOrder": false }, { "heading": "tab2", "imagePath": "/media/1005/why-automate-testing.jpg", "id": "pGropEditor2", "content": "ndustry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. is simply dummy text of the printing and typesetting i", "revertOrder": true }, { "heading": "tab3", "imagePath": null, "id": "pGropEditor3", "content": "ndustry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. is simply dummy text of the printing and typesetting i", "revertOrder": false }, { "heading": "tab4", "imagePath": null, "id": "pGropEditor4", "content": "ndustry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. is simply dummy text of the printing and typesetting i", "revertOrder": true } ], "heading": "Main Paragraph Heading", "tabData": [ { "heading": "tab1", "imagePath": "/media/1010/test.png", "id": "pGropEditor1", "content": "yogesh", "revertOrder": false }, { "heading": "tab2", "imagePath": "/media/1005/why-automate-testing.jpg", "id": "pGropEditor2", "content": "ndustry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. is simply dummy text of the printing and typesetting i", "revertOrder": true }, { "heading": "tab3", "imagePath": null, "id": "pGropEditor3", "content": "ndustry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. is simply dummy text of the printing and typesetting i", "revertOrder": false }, { "heading": "tab4", "imagePath": null, "id": "pGropEditor4", "content": "ndustry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. is simply dummy text of the printing and typesetting i", "revertOrder": true } ], "mainHeading": "Main Paragraph Heading" } ] } ], "id": "59195606-2ce2-d82a-6178-12091aa8898b" } ] } ] }

    Tablesdata and mainHeading are the object i need to index

    Hope it show better picture of my problem

    yogesh

  • Anders Bjerner 487 posts 2990 karma points MVP 8x admin c-trib
    Jul 30, 2015 @ 16:12
    Anders Bjerner
    0

    That helps a bit :D

    It is however worth mentioning that the way you're saving your data is a bit wrong. In the JSON you have added properties directly to the object representing the control, whereas they should ideally be added to the value object.

    So rather than saving tabelsData to $scope.control.tabelsData, you should ideally save it to $scope.control.value.tabelsData.

    Working with the existing editor / JSON value
    My package has a converter system that lets you add new models for your custom editors. Since your data isn't saved as the value object, we can't utilize this system.

    Instead we can work directly with the JObject's and JArray's representing the JSON. You can see this little example on how to read the different values:

    using System;
    using Newtonsoft.Json.Linq;
    using Skybrud.Umbraco.GridData;
    using Skybrud.Umbraco.GridData.Extensions.Json;
    
    namespace ConsoleApplication1 {
    
        public class Hest {
    
            public static void Test(GridDataModel model) {
    
                foreach (GridControl control in model.GetAllControls("paragraphGroup")) {
    
                    // Get the value of "mainHeading"
                    string mainHeading = control.JObject.GetString("mainHeading");
    
                    // Get the value of "heading"
                    string heading = control.JObject.GetString("heading");
    
                    // Write to the console (or add to index)
                    if (!String.IsNullOrWhiteSpace(mainHeading)) { Console.WriteLine(mainHeading); }
                    if (!String.IsNullOrWhiteSpace(heading)) { Console.WriteLine(heading); }
    
                    // Get the array representing "tabelsData"
                    JArray tabelsData = control.JObject.GetArray("tabelsData");
    
                    // Make sure to check whether the array is null
                    if (tabelsData != null) {
    
                        // Iterate through the objects in the array
                        foreach (JObject obj in tabelsData) {
    
                            // get the "content" property
                            string content = obj.GetString("content");
    
                            // Write to the console (or add to index)
                            if (!String.IsNullOrWhiteSpace(content)) { Console.WriteLine(content); }
    
                        }
    
                    }
    
                }
    
            }
    
        }
    
    }
    

    My example simply writes the values to the console, but you could just as easily add them to the search index ;)

    Using the build-in converter system

    Creating a custom converter has a few steps, so it may take a bit more work to get implemented. A benefit is that it will make your code and views cleaner.

    This also assumes that you have fixed your editor to save your data to $scope.control.value instead of just $scope.control.

    First you need to implement a model representing your JSON data. I have done this for you with the ParagraphGroupControlValue and ParagraphGroupTableData classes. I haven't added all properties though.

    ParagraphGroupControlValue.cs:

    using Newtonsoft.Json.Linq;
    using Skybrud.Umbraco.GridData;
    using Skybrud.Umbraco.GridData.Extensions.Json;
    using Skybrud.Umbraco.GridData.Interfaces;
    using Skybrud.Umbraco.GridData.Json;
    
    namespace ConsoleApplication1 {
    
        public class ParagraphGroupControlValue : GridJsonObject, IGridControlValue {
    
            #region Properties
    
            public GridControl Control { get; private set; }
    
            public string MainHeading { get; private set; }
    
            public string Heading { get; private set; }
    
            public ParagraphGroupTableData[] TableData { get; private set; }
    
            #endregion
    
            #region Constructors
    
            protected ParagraphGroupControlValue(JObject obj) : base(obj) { }
    
            #endregion
    
            #region Static methods
    
            public static ParagraphGroupControlValue Parse(GridControl control, JObject obj) {
                if (obj == null) return null;
                return new ParagraphGroupControlValue(obj) {
                    Control = control,
                    MainHeading = obj.GetString("mainHeading"),
                    Heading = obj.GetString("heading"),
                    TableData = obj.GetArray("tabelsData", ParagraphGroupTableData.Parse) ?? new ParagraphGroupTableData[0]
                };
            }
    
            #endregion
    
        }
    
    }
    

    ParagraphGroupTableData.cs:

    using Newtonsoft.Json.Linq;
    using Skybrud.Umbraco.GridData.Extensions.Json;
    using Skybrud.Umbraco.GridData.Json;
    
    namespace ConsoleApplication1 {
    
        public class ParagraphGroupTableData : GridJsonObject {
    
            #region Properties
    
            public string Heading { get; private set; }
            public string ImagePath { get; private set; }
            public string Id { get; private set; }
            public string Content { get; private set; }
            public bool RevertOrder { get; private set; }
    
            #endregion
    
            #region Constructors
    
            protected ParagraphGroupTableData(JObject obj) : base(obj) { }
    
            #endregion
    
            #region Static methods
    
            public static ParagraphGroupTableData Parse(JObject obj) {
                if (obj == null) return null;
                return new ParagraphGroupTableData(obj) {
                    Heading = obj.GetString("heading"),
                    ImagePath = obj.GetString("imagePath"),
                    Id = obj.GetString("id"),
                    Content = obj.GetString("content"),
                    RevertOrder = obj.GetBoolean("revertOrder")
                };
            }
    
            #endregion
    
        }
    
    }
    

    The first class represents the object stored in the value property, while the second class represents each object in the tabelsData array.

    The next step is to implement a custom converter - this is done by implementing the IGridConverter interface. For your editor, this could look like:

    using Newtonsoft.Json.Linq;
    using Skybrud.Umbraco.GridData;
    using Skybrud.Umbraco.GridData.Extensions.Json;
    using Skybrud.Umbraco.GridData.Interfaces;
    using Skybrud.Umbraco.GridData.Rendering;
    
    namespace ConsoleApplication1 {
    
        public class ParagraphGroupGridConverter : IGridConverter {
    
            public virtual bool ConvertControlValue(GridControl control, JToken token, out IGridControlValue value) {
    
                value = null;
    
                switch (control.Editor.Alias) {
    
                    case "paragraphGroup":
                        value = ParagraphGroupControlValue.Parse(control, token as JObject);
                        break;
    
                }
    
                return value != null;
    
            }
    
            public virtual bool ConvertEditorConfig(GridEditor editor, JToken token, out IGridEditorConfig config) {
                config = null;
                return false;
            }
    
            public virtual bool GetControlWrapper(GridControl control, out GridControlWrapper wrapper) {
    
                wrapper = null;
    
                switch (control.Editor.Alias) {
    
                    case "paragraphGroup":
                        wrapper = control.GetControlWrapper<ParagraphGroupControlValue>();
                        break;
    
                }
    
                return wrapper != null;
    
            }
    
        }
    
    }
    

    To quickly summarize the class, the ConvertControlValue method makes sure the value is properly converted - eg. so that you can call control.GetValue<ParagraphGroupControlValue>().

    The ConvertEditorConfig method convert the configuration of the editor. Not sure whether you're using the configuration for anything, the converter does nothing at that point.

    Finally the GetControlWrapper method tells my package how it should initialize a wrapper for the class. The wrapper is something that can be used in your views, so it isn't really necessary for indexing.

    Since the both the model and the converter are now in place, the last step is to tell my package about the converter. The converted should be added during Umbraco startup, which can be done similar to:

    using Skybrud.Umbraco.GridData;
    using Umbraco.Core;
    
    namespace ConsoleApplication1 {
    
        public class Startup : IApplicationEventHandler {
    
            public void OnApplicationStarted(UmbracoApplicationBase umbraco, ApplicationContext context) {
                GridContext.Current.Converters.Add(new ParagraphGroupGridConverter());
            }
    
            public void OnApplicationStarting(UmbracoApplicationBase umbraco, ApplicationContext context) { }
    
            public void OnApplicationInitialized(UmbracoApplicationBase umbraco, ApplicationContext context) { }
    
        }
    
    }
    

    So rather than the first code example in the top of this post, the same class could now look like:

    using System;
    using Skybrud.Umbraco.GridData;
    
    namespace ConsoleApplication1 {
    
        public class Hest {
    
            public static void Test(GridDataModel model) {
    
                foreach (GridControl control in model.GetAllControls("paragraphGroup")) {
    
                    // Get the strongly typed value
                    ParagraphGroupControlValue value = control.GetValue<ParagraphGroupControlValue>();
    
                    // Write to the console (or add to index)
                    if (!String.IsNullOrWhiteSpace(value.MainHeading)) { Console.WriteLine(value.MainHeading); }
                    if (!String.IsNullOrWhiteSpace(value.Heading)) { Console.WriteLine(value.Heading); }
    
                    // Iterate through the table data in the array
                    foreach (ParagraphGroupTableData data in value.TableData) {
    
                        // Write to the console (or add to index)
                        if (!String.IsNullOrWhiteSpace(data.Content)) { Console.WriteLine(data.Content); }
    
                    }
    
                }
    
            }
    
        }
    
    }
    

    I know that working with the grid can be a bit complex, so let me know if you have any further questions ;)

  • yogesh pathak 136 posts 221 karma points
    Jul 31, 2015 @ 04:54
    yogesh pathak
    0

    Thank you so much for the detailed explanation :)

    i am going to change my Grid Controller code (adding the value part) and then implementing This solution , i will get back to you by today EOD with more question ;)

    Thanks

    Yogesh

  • yogesh pathak 136 posts 221 karma points
    Aug 03, 2015 @ 06:54
    yogesh pathak
    0

    Hi Anders,

    Thanks for guiding me to clean my code it looks way better then it was :)

    I Have implemented your solution and checked indexes by Luke.net and good news is it working :) , Indexes are being created for Paragraph Group editor grid control . Now i have few queries and to do implementation , for which i want to have suggestions from you before following any approach

    1. I have my website structured in a way where i have two main nodes -1st one is My web site and second one is grid repository in grid repository i used to create Content using my grid editors and in my website node i used to pick those created content by multi node tree picker . i have followed this approach because i wanted to use my content to be reusable and can be picked up in container manner , so now the situation is my implementation indexes grid repository content one by one and will show results of same but what i want is it should index the grid repository node and in the search result page it should redirect user into my website node where the content actually picked (not where it is created which is currently the case) . so any suggestions to achieve this?

    2. how can i create custom fields in External Indexer?

    Thanks

    Yogesh

  • Anders Bjerner 487 posts 2990 karma points MVP 8x admin c-trib
    Aug 03, 2015 @ 12:41
    Anders Bjerner
    0
    1. The way I understand you, you have some kind of grid picker on your regular pages? Then when these pages are being indexed, you could make lookups in the content cache for the selected grid pages. How to accomplish this depends a lot on your solution and current code, so I might not be able to help much with this one.

    2. If you have a look at my example, I'm adding the combined search value fro the grid into a new field e.Fields["content"] = combined.ToString();. So to add a new field, you could jsut do something like e.Fields["myNewField"] = "Hello World";.

  • yogesh pathak 136 posts 221 karma points
    Aug 03, 2015 @ 12:54
    yogesh pathak
    0

    1-Yes i have grid picker in my regular pages , these pages are not getting index as per the data they show to the user because they contains only Id of content 2-Ok Thanks , i thought we have to sett this "Content" property on web config or somewhere

    I am working on 1 point , i will post here if i will come across a solution

    Thanks for help :)

  • yogesh pathak 136 posts 221 karma points
    Aug 06, 2015 @ 03:51
    yogesh pathak
    0

    Hi Anders, I have a razor macro with static content (i.e Addressees) but i am not able to search this content with examine any help on this?

    thanks

    Yogesh

  • Anders Bjerner 487 posts 2990 karma points MVP 8x admin c-trib
    Aug 06, 2015 @ 17:54
    Anders Bjerner
    0

    This is a bit out of the scope of my package, and again, it depends a lot on your solution.

    If the addresses are static (hardcoded?) you can just add new field(s) for these when the relevant nodes are being indexed.

  • yogesh pathak 136 posts 221 karma points
    Aug 07, 2015 @ 04:43
    yogesh pathak
    0

    ok Thanks :)

    Yogesh

  • yogesh pathak 136 posts 221 karma points
    Aug 25, 2015 @ 17:18
    yogesh pathak
    0

    Hi Anders, i m trying to create my own custom index set Instead of using External index set , but not able to get "content" field in it . my configuration is as bellow

    <IndexSet SetName="MySearchIndexSet" IndexPath="~/App_Data/ExamineIndexes/MySearchIndexSet/">
    <IndexAttributeFields>
      <add Name="id" />
      <add Name="nodeName"/>
      <add Name="nodeTypeAlias"/>
    </IndexAttributeFields>
    <IndexUserFields>
      <add Name="ContainerLinks"/>
      <add Name="SearchableContent"/>
      <add Name="ContentHeading"/>
      <add Name="editor"/>
      <add Name="SubHeading"/>
      <add Name="content"/>
    </IndexUserFields>
    <IncludeNodeTypes>
      <add Name="Container" />
      <add Name="Containerfolders" />
      <add Name="GenericPages" />
      <add Name="Home" />
    </IncludeNodeTypes>
    

    can you help?

    Thanks

    Yogesh

Please Sign in or register to post replies

Write your reply to:

Draft