Editor: Is there an API to manually access data the field type select uses?

Editor: Is there an API to manually access data the field type select uses?

avitavit Posts: 5Questions: 1Answers: 0
edited February 2018 in Free community support

I can see the data in the json response: draw.options, but how to access this properly.

So basically instead of using a select, I want to show a readonly value from the options, when I create a new entry.

fields: [
                {
                    label: "MyLabel",
                    name: "mytable.mycolumn",
                    type : "select"
                },
            ]

I tried solving it by using a def value.

fields: [
                {
                    label: "MyLabel",
                    name: "mytable.name",
                    type: "readonly",
                    def: function () {                        
                        return table.data().options().myOptionTable.MyField;
                    }
                },
            ]

Obviously this doesn't work.

.Field(new Field("mytable.myforeignkey")
                        .Options(new Options()
                            .Table("foreigntable")
                            .Value("id")
                            .Label("name")
                        )
                    )

I don't find any interface to properly access the options.

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    I'm afraid I'm not fully understanding what you are looking for here. Do you want the select field to not be enabled (i.e. have it as readonly)? If so, disable() or field().disable() is the way to do that.

    Regards,
    Allan

  • avitavit Posts: 5Questions: 1Answers: 0

    No, sorry I'm not a good explainer :/

    Think of a master detail view and I want to add details to the master, e.g. I want to add ingredients to a recipe, but I want to show the recipe id and name in the ingredient editor view. I cannot use a left join, because the editor fields would be empty when I create a new entry.

    So my idea was, to use the primary key of the recipe, that is allready part of my backend model and ask the options API of DataTables.Editor for the correct recipe name.

    When I think about it, a right join or inner join could also work, but DataTables.Editor .Net doesn't seem support them.

    Thanks

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Perhaps this plug-in will be of some help? If I'm understanding what you want correctly, you want to just display some information to the end user in the form, which is something that plug-in makes possible.

    Allan

  • avitavit Posts: 5Questions: 1Answers: 0
    edited February 2018

    Unfortunately this is not what I need, I could use it at some point when my problem is solved though :p

    So let's go deeper here, I created a minimal example to explain the concept.

    1. This is my model
    2. Recipe table
    3. Edit specific recipe ingredients
    4. Create new entry - missing recipe name
    5. Recipe name is there in edit form because of left joined data

    Recipe view code

    <script>
        var editor;
    
        $(document).ready(function () {
            editor = new $.fn.dataTable.Editor({
                ajax: "/api/recipe",
                table: "#recipe",
                fields: [
                {
                    label: "Recipe",
                    name: "recipe.name"
                }
                ]
            });
    
            var table = $('#recipe').DataTable({
                dom: "Bfrtip",
                ajax: "/api/recipe",
                processing: true,
                serverSide: true,
                deferRender: true,
                searchDelay: 500,
                paging: true,
                searching: true,
                search: {
                    smart: true,
                    regex: false
                },
                columns: [
                    { data: "recipe.id" },
                    { data: "recipe.name" },
                ],
                select: true,
                buttons: [
                    { extend: "create", editor: editor },
                    { extend: "edit", editor: editor },
                    { extend: "remove", editor: editor },
                    {
                        text: "Edit Recipe",
                        action: function (e, dt, node, config) {
                            var idx = table.row({ selected: true }).index();
                            var data = table.row( idx ).data();
    
                            window.location.href = window.location.origin + "/recipe-ingredient/" + data.recipe.id;
                        }
                    }
            ]
        });
        });
    </script>
    
    <script>
        var id = @Model.Id;
        var editor;
        var table;
    
        $(document).ready(function () {
            editor = new $.fn.dataTable.Editor({
                ajax: "/api/recipe-ingredient/" + "@Model.Id",
                table: "#recipe-ingredient",
                fields: [
                    {
                        label: "Recipe ID",
                        name: "recipe_ingredient.recipe",
                        def: "@Model.Id",
                        type : "readonly"
                    },
                    {
                        label: "Recipe",
                        name: "recipe.name", // I want the recipe name here regardless of when I click "Create New" or "Edit"
                        type: "readonly",
                    },
                    {
                        label: "Ingredient",
                        name: "recipe_ingredient.ingredient",
                        type: "select"
                    },
                    {
                        label: "Amount",
                        name: "recipe_ingredient.amount"
                    }
                ]
            });
    
            $('#recipe-ingredient').on( 'click', 'tbody td:not(:first-child)', function (e) {
                editor.inline( this );
            } );
    
            table = $('#recipe-ingredient').DataTable({
                dom: "Bfrtip",
                ajax: "/api/recipe-ingredient/"+ "@Model.Id",
                processing: true,
                serverSide: true,
                deferRender: true,
                searchDelay: 500,
                paging: true,
                searching: true,
                search: {
                    smart: true,
                    regex: false
                },
                columns: [
                    { data: "recipe_ingredient.id" },
                    { data: "ingredient.name", editField: "recipe_ingredient.ingredient" },
                    { data: "recipe_ingredient.amount" },
                ],
                select: true,
                buttons: [
                    { extend: "create", editor: editor },
                    { extend: "edit", editor: editor },
                    { extend: "remove", editor: editor }
                ]
            });
        });
    </script>
    

    Back end code

    public class RecipeIngredientModule : NancyModule
        {
            public RecipeIngredientModule()
            {
                Get["/recipe-ingredient/{id}"] = x =>
                {
                    int id = x.id;
                    var model = new ModelBase("Edit recipe");
                    model.Id = id;
                    return View["cooking/recipe_ingredient", model];
                };
    
    
                Get["/api/recipe-ingredient/{id}"] = x =>
                {
                    int id = x.id;
                    return GetRecipeIngredient(x, id);
                };
    
                Post["/api/recipe-ingredient/{id}"] = x =>
                {
                    int id = x.id;
                    return GetRecipeIngredient(x, id);
                };
            }
    
            public Response GetRecipeIngredient(dynamic x, int id)
            {
                Editor editor = GetEditor(x, id);
                return Response.AsJson(editor.Data());
            }
    
            public Editor GetEditor(dynamic x, int id)
            {
                var settings = Properties.Settings.Default;
    
                using (var db = new Database(settings.DbType, settings.DbConnection))
                {
                    Editor response = new Editor(db, "recipe_ingredient", "id")
                        .Model<RecipeIngredientModel>()
                        .Field(new Field("recipe_ingredient.id"))
                        .Field(new Field("recipe_ingredient.recipe")
                            .Options(new Options()
                                .Table("recipe")
                                .Value("id")
                                .Label("name")
                            )
                            .SetValue(id)
                        )
                        .Field(new Field("recipe_ingredient.ingredient")
                            .Options(new Options()
                                .Table("ingredient")
                                .Value("id")
                                .Label("name")
                            )
                        )
                        .Field(new Field("recipe.id"))
                        .Field(new Field("recipe.name"))
                        .Field(new Field("ingredient.id"))
                        .Field(new Field("ingredient.name"))
                        .Field(new Field("recipe_ingredient.amount"))
                        .LeftJoin("recipe", "recipe.id", "=", "recipe_ingredient.recipe")
                        .LeftJoin("ingredient", "ingredient.id", "=", "recipe_ingredient.ingredient")
                        .Where("recipe.id", id, "=")
                        .Process(ToList(Request));
    
                    return response;
                }
            }
    
            public IEnumerable<KeyValuePair<string, string>> ToList(Request request)
            {
                dynamic data = request.Query;
    
                if (request.Method == "POST")
                {
                    data = request.Form;
                }
    
                return ((IDictionary<string, object>)data).ToDictionary(x => x.Key, x => x.Value.ToString()).ToList();
            }
        }
    

    I have a recipe table that redirects to the recipe-ingredient view, as soon as someone clicks on edit recipe.

    In the "Create new entry" (Picture 4.) form I want to have "Pancake" there even when I click on "Create".

    What is the best way to achieve that?

    I'm using NancyFX as backend, but the code should be straightforward.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Thanks for the details!

    In the code above you have def: "@Model.Id", for the id field. Can you do something similar for the name field? Is it possible to add the name to your model, so that if the Id parameter is defined, the Name parameter would also be so?

    If that isn't possible then the way to solve it shown the way you have above is to put an event listener on the recipe_ingredient.recipe to detect a change in value for that field. When that change is detected, you could either make an Ajax call to the server to determine what the correct name is for the id, or if that information is available in a local object, look it up there.

    You could use either dependent() for that or field().input() and assign a custom event listener.

    Does that all make sense?

    Thanks,
    Allan

  • avitavit Posts: 5Questions: 1Answers: 0
    edited February 2018

    Hey allan,

    thanks for staying with me ;)

    If that isn't possible then the way to solve it shown the way you have above is to put an event listener on the recipe_ingredient.recipe to detect a change in value for that field. When that change is detected, you could either make an Ajax call to the server to determine what the correct name is for the id, or if that information is available in a local object, look it up there.

    Exactly this, the data is already available as local object, in the depths of DataTables and I want know how to access them properly with DataTables.Editor ;)

    See, this is the response of my backend, generated by datatables.editor .net, the field is already there, waiting for me to be used.

    Sure I could just request the data again, but I would like to avoid that.

    Thanks again.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin
    Answer ✓

    Okay - with you now!

    ajax.json() will give you the latest JSON that DataTables has got back from the server - so you could do:

    editor.field( 'recipe_ingredient.recipe' ).input().on( 'change', function () {
      var id = this.value;
      var options = table.ajax.json().options['recipe_ingredient.recipe'];
    
      for ( var i=0, ien=options.length ; i<ien ; i++ ) {
        if ( options[i].value == id ) {
          editor.field('recipe.name').val( options[i].label );
          break;
        }
      }
    } );
    

    I think that should more or less do it.

    Allan

  • avitavit Posts: 5Questions: 1Answers: 0

    Thank you Allan,

    That does the job indeed.
    Now I'm weighing my options and see what fits best.

    Best regards

This discussion has been closed.