One-to-many file upload with additional checkbox

One-to-many file upload with additional checkbox

ezdavisezdavis Posts: 35Questions: 3Answers: 0

Link to test case:
Debugger code (debug.datatables.net):
Error messages shown:
Description of problem:
I have a one to many file upload setup following your example using a link table. My image model looks like the following

public class ImagesModel : EditorModel
    {
        public System.Guid ImageID { get; set; }
        public byte[] Content { get; set; }
        public string ContentType { get; set; }
        public string Extension { get; set; }
        public string FileName { get; set; }
        public int FileSize { get; set; }
        public string MimeType { get; set; }
        public DateTime CreatedDate { get; set; }
        public bool IsDefault { get; set; }
    }

Basically, I have "Products" that can have many images. This is all setup and working fine with all images currently being uploaded as "IsDefault" false. However, I need a way to mark the "IsDefault". I want to have a checkbox next to the image and then a validator in my controller to only allow 1 image to be checked but I'm struggling on how to accomplish this. Any suggestions? Here's my editor

using (var db = new Database(dbType, dbConnection))
            {
                var response = new Editor(db, "Product.Product", "ProductID")
                    //.Model<ProductModel>()
                    .Field(new Field("ProductID"))
                    .Field(new Field("Product.ProductID").Set(false))
                    .Field(new Field("Product.Identifier").Set(false))
                    .Field(new Field("Product.Title").Set(false))
                    .MJoin(new MJoin("Product.Images")
                        .Link("Product.Product.ProductID", "Product.ImageRef.ProductID")
                        .Link("Product.Images.ImageID", "Product.ImageRef.ImageID")
                        .Model<ImagesModel>()
                        .Field(new Field("ImageID")
                            .Upload(new Upload()
                                .Db("Product.Images", "ImageID", new Dictionary<string, object>
                                {
                                    //{"web_path", Path.DirectorySeparatorChar+Path.Combine("uploads", "__ID____EXTN__")},
                                    {"ImageID", Upload.DbType.ReadOnly},
                                    {"Content", Upload.DbType.ContentBinary},
                                    {"ContentType", Upload.DbType.ContentType},
                                    {"Extension", Upload.DbType.Extn},
                                    {"FileName", Upload.DbType.FileName},
                                    {"FileSize", Upload.DbType.FileSize},
                                    {"MimeType", Upload.DbType.MimeType},
                                    {"CreatedDate", Upload.DbType.ReadOnly},
                                    {"IsDefault", Upload.DbType.ReadOnly}
                                })
                                .Validator(Validation.FileSize(500000, "Max file size is 500K."))
                                .Validator(Validation.FileExtensions(new[] { "jpg", "png", "jpeg" }, "Please upload an image."))
                                )
                        )
                    )
                    //.Debug(true).TryCatch(false)
                    .Process(Request)
                    .Data();

                return Json(response);
            }

Note: I have IsDefault setup as a bit in my database and defaults to 0.

Thanks for any help you can provide.

«1

Answers

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Hi,

    With the values in the Dictionary for the third parameter to Db(), you don't just need to use the Upload.DbType enum - you can also use values or even a delegate. So for example:

    {"IsDefault", false}
    

    would write false into the IsDefault database field.

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Sorry, just getting back to this

    So when I try as you suggest with false,true,0, or 1 I get the error -

    "Conversion failed when converting the nvarchar value '-' to data type bit."

    Once I get this error fixed how could I get the value of the checkbox. Please see my js below that shows how I display a checkbox by my image in the UploadMany (I have my own logic for displaying image by UID but the part I'm trying to get the value of is the checkbox). How could I get the value of this checkbox to be updated with my image?

    var editor; // use a global for the submit and return data rendering in the examples
    
    $(document).ready(function () {
        editor = new $.fn.dataTable.Editor({
            ajax: "/file/LoadAllImages",
            table: "#example",
            fields: [
                {
                    label: "Product ID:",
                    name: "Product.ProductID",
                    type: "readonly"
                },
                {
                label: "Part No:",
                    name: "Product.Identifier",
                    type: "readonly"
                },
                {
                label: "Title:",
                name: "Product.Title",
                type: "readonly"
                },
                {
                label: "Images:",
                name: "Images[].ImageID",
                type: "uploadMany",
                    display:
                        function (fileId, counter) {
                            return '<img src="http://localhost:44328/UID/' + editor.file('Product.Images', fileId).ImageID + editor.file('Product.Images', fileId).Extension + '"/> <input type="checkbox" id="' + editor.file('Product.Images', fileId).ImageID + '" name="' + editor.file('Product.Images', fileId).FileName + '" checked="' + editor.file('Product.Images', fileId).IsDefault + '">';
                    }
                    ,
                noFileText: 'No images'
            }
            ]
        });
    
        $('#example').DataTable({
            dom: "Bfrtip",
            ajax: {
                url: "/file/LoadAllImages",
                type: 'POST'
            },
            serverSide: "true",
            processing: "true",
            columns: [
                { data: "Product.ProductID" },
                { data: "Product.Identifier"},
                { data: "Product.Title" },
                {
                    data: "Images",
                    render: function (d) {
                        return d.length ?
                            d.length + ' image(s)' :
                            'No image';
                    },
                    title: "Image"
                }
            ],
            select: true,
            buttons: [
                { extend: "create", editor: editor },
                { extend: "edit", editor: editor },
                { extend: "remove", editor: editor }
            ]
        });
    });
    
  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Can you show me the schema for your table please?

    Thanks,
    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    I also have the Product.Product table but items are added to that separately. All I'm trying to do is add the ability to setup multiple images per product (Which works). And then mark one as the default image for the product.

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Many thanks. What version of the DataTables dll is it you are using? What should be happening is that the ReadOnly flag hits here and there is no write to the database on that column.

    But it looks like it might be getting down to line 687 for some reason and trying to set the column to be a dash, causing the error you are seeing.

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    2.0.4 is the version I'm using.

    It would make sense that it's hitting line 687 if I'm changing

    {"IsDefault", Upload.DbType.ReadOnly}
    

    to

    {"IsDefault", false}
    

    right?

    It's no longer a DbType. Should it be hitting completely separate logic for a value rather than a DbType?

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    You are spot on - it didn't quite click for me first thing this morning!

    The most obvious change is to simply remove those two q.Set calls, but there might be some who are depended upon this behaviour (it would need a default value in SQL for the target column). I could try setting it to null, but equally the column would need to allow null values.

    My inclination is to remove those two calls with Editor 2.1 (although I don't have a time scale for that yet). You could build the dlls from source with those lines removed, or I can send you over built ones if you prefer?

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Yeah, if you could send me the built files I could try it out.

    But would I need to to use a delegate to get the value from my checkbox for IsDefault? Do you have an example of an upload that uses a delegate?

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    No you shouldn't need to use a delegate. The try/catch should handle cases where a non-delagate is given. However, you could use {"IsDefault", () => false} which is a simple lambda for it.

    The dll's are here.

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Alright so I've tested it and I'm no longer getting an error but I don't think it's actually doing anything.

    I have my table defaulting the IsDefault to false in SQL.

    When I set

    {"IsDefault", true}
    

    the column is still set false. When I check my checkbox nothing happens there either it always stays false.

    When I set

    {"IsDefault", () => false}
    

    I get the error "Cannot convert lambda expression to type 'object' because it is not a delegate type"

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Could you possibly try:

    {"IsDefault", 1}
    

    please? That worked for me (using MySQL as the database with a boolean field).

    Sorry about the delegate - I'm to used to writing Javascript. It would need to be more along the lines of:

    (Func<Database, IFormFile, ojbect>)((d, f) => "1")},
    

    That isn't quite right though - there is a cast missing in the dll I sent you. Hopefully using the {"IsDefault", 1} will do the job for you though.

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    That didn't work for me either. Here are my 3 tables being used if you would like to create your own tables to try it.

    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [Product].[Product](
        [ProductID] [int] IDENTITY(1,1) NOT NULL,
        [Identifier] [varchar](50) NOT NULL,
        [Title] [varchar](300) NOT NULL,
     CONSTRAINT [PK_Product_1] PRIMARY KEY CLUSTERED 
    (
        [ProductID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [Product].[Images](
        [ImageID] [uniqueidentifier] NOT NULL,
        [Content] [varbinary](max) NOT NULL,
        [ContentType] [varchar](50) NULL,
        [Extension] [varchar](50) NULL,
        [FileName] [nvarchar](50) NULL,
        [FileSize] [int] NULL,
        [MimeType] [nvarchar](50) NULL,
        [CreatedDate] [datetime] NULL,
        [IsDefault] [bit] NOT NULL,
     CONSTRAINT [PK_Images] PRIMARY KEY CLUSTERED 
    (
        [ImageID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO
    
    ALTER TABLE [Product].[Images] ADD  DEFAULT (newid()) FOR [ImageID]
    GO
    
    ALTER TABLE [Product].[Images] ADD  CONSTRAINT [DF_Images_CreatedDate]  DEFAULT (getdate()) FOR [CreatedDate]
    GO
    
    ALTER TABLE [Product].[Images] ADD  CONSTRAINT [DF_Images_IsDefault]  DEFAULT ((0)) FOR [IsDefault]
    GO
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [Product].[ImageRef](
        [ImageID] [uniqueidentifier] NOT NULL,
        [ProductID] [int] NOT NULL,
     CONSTRAINT [PK_ImageRef_1] PRIMARY KEY CLUSTERED 
    (
        [ImageID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    
    ALTER TABLE [Product].[ImageRef]  WITH CHECK ADD  CONSTRAINT [FK_ImageRef_Images] FOREIGN KEY([ImageID])
    REFERENCES [Product].[Images] ([ImageID])
    GO
    
    ALTER TABLE [Product].[ImageRef] CHECK CONSTRAINT [FK_ImageRef_Images]
    GO
    
    ALTER TABLE [Product].[ImageRef]  WITH CHECK ADD  CONSTRAINT [FK_ImageRef_Product] FOREIGN KEY([ProductID])
    REFERENCES [Product].[Product] ([ProductID])
    GO
    
    ALTER TABLE [Product].[ImageRef] CHECK CONSTRAINT [FK_ImageRef_Product]
    GO
    
  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Hey Allan,

    Thanks for your help so far. Do you have any other suggestions on how to get this to work? I'm so close I just need to mark one as the default image somehow. I could even create another table to link to and then update somehow if that makes sense. Do you have any suggestions? Thanks.

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Could you comment back in the .Debug(true) and then from the response to the upload action, show me the JSON that the server is returning please? I'm surprised that {"IsDefault", 1} isn't working.

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Here is the part that gets returned after I select the image. Looks like it uploads the image to the table when you select it and when you click update it does another call to update the ref table with the ID.

    {
        "draw": null,
        "data": [],
        "recordsTotal": null,
        "recordsFiltered": null,
        "error": null,
        "fieldErrors": [],
        "id": null,
        "meta": {},
        "options": {},
        "searchPanes": {
            "options": {}
        },
        "files": {
            "Product.Images": {
                "e4c8f4d7-dd0c-4287-a8d5-9c243bb48a63": {
                    "ImageID": "e4c8f4d7-dd0c-4287-a8d5-9c243bb48a63",
                    "ContentType": "image/jpeg",
                    "Extension": ".jpg",
                    "FileName": "Logo_2Color_tag.jpg",
                    "FileSize": 174001,
                    "MimeType": "image/jpeg",
                    "CreatedDate": "2021-10-06T09:32:03.29",
                    "IsDefault": false
                }
            }
        },
        "upload": {
            "id": "e4c8f4d7-dd0c-4287-a8d5-9c243bb48a63"
        },
        "debug": [{
                "Query": "DECLARE @T TABLE ( insert_id uniqueidentifier ); INSERT INTO  [Product].[Images]  ( [Content], [ContentType], [Extension], [FileName], [FileSize], [MimeType] ) OUTPUT INSERTED.ImageID as insert_id INTO @T VALUES (  @Content,  @ContentType,  @Extension,  @FileName,  @FileSize,  @MimeType ); SELECT insert_id FROM @T",
                "Bindings": [{
                        "Name": "@Content",
                        "Value": "LARGEIMAGEVALUEWASHEREBUTREMOVED",
                        "Type": null
                    }, {
                        "Name": "@ContentType",
                        "Value": "image/jpeg",
                        "Type": null
                    }, {
                        "Name": "@Extension",
                        "Value": ".jpg",
                        "Type": null
                    }, {
                        "Name": "@FileName",
                        "Value": "Logo_2Color_tag.jpg",
                        "Type": null
                    }, {
                        "Name": "@FileSize",
                        "Value": 174001,
                        "Type": null
                    }, {
                        "Name": "@MimeType",
                        "Value": "image/jpeg",
                        "Type": null
                    }
                ]
            }, {
                "Query": "SELECT  [ImageID] as 'ImageID', [ContentType] as 'ContentType', [Extension] as 'Extension', [FileName] as 'FileName', [FileSize] as 'FileSize', [MimeType] as 'MimeType', [CreatedDate] as 'CreatedDate', [IsDefault] as 'IsDefault' FROM  [Product].[Images] WHERE [ImageID] IN (@wherein1) ",
                "Bindings": [{
                        "Name": "@wherein1",
                        "Value": "e4c8f4d7-dd0c-4287-a8d5-9c243bb48a63",
                        "Type": null
                    }
                ]
            }
        ],
        "cancelled": []
    }
    

    NOTE: I removed the actual image from content value to make the json smaller.

    The one thing I notice is the first debug inserts the table without "CreatedDate" or "IsDefault"

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    I might have realised what the problem is - the DbType is an enum, which is causing to conflict with just passing in 1 for example.

    Let me get back to you on this tomorrow - I've got a plan...

    Allan

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Actually - I've just gone ahead and tried it out... :).

    Try:

    {"IsDefault", (Func<Database, IFormFile, dynamic>)((d, f) => 1)}
    

    with this dll.

    That does the job for me locally with SqlServer.

    We need to use the anonymous function after all since just using 1 would cause it to match against the DbType enum!

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    I get an error when trying to add the dll to my project. Can you send me a link like before that has the debug folder and the different net folders and dll's inside of it? Thanks

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Sorry - it is actually a zip file, but I used the wrong extension. Here it is with the correct .zip extension.

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    I've tested the change and it works so thank you for that!

    I think I've almost got my process down but having one more issue.

    I've added more fields that are nullable to the Product.Images table. I've then followed this blog https://datatables.net/blog/2019-01-11 to add a parent/child row that has a datatable for editing details. All loads fine but when clicking update in editor my database isn't updated although the call is successful. When I check the network tab in chrome I can see the form data in my request contains

    data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][ImageID]: c6000f4a-1dde-4a5f-a80a-92e4e867fdc1
    data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][FileName]: LinksUnlimited_Logo_2Color_tag.jpg
    data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][IsDefault]: 1
    data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][AngleID]: 5
    data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][Importance]: 1
    action: edit
    ProductID: 106
    

    and I can also see this if I debug my controller action in my Request.Form, however nothing gets updated. When I check the debug of the response it's only doing a select query. Any idea why nothing is being updated even though it's getting the edit action and details?

    Here is the controller actions and the js is posted in another comment due to length

    [HttpGet]
    [HttpPost]
    public ActionResult LoadAllImages()
    {
        using (var db = new Database(dbType, dbConnection))
        {
            var response = new Editor(db, "Product.Product", "ProductID")
                .Model<ProductModel>()
                .Field(new Field("ProductID"))
                .MJoin(new MJoin("Product.Images")
                    .Link("Product.Product.ProductID", "Product.ImageRef.ProductID")
                    .Link("Product.Images.ImageID", "Product.ImageRef.ImageID")
                    .Model<ImagesModel>()
                    .Field(new Field("ImageID")
                        .Upload(new Upload()
                            .Db("Product.Images", "ImageID", new Dictionary<string, object>
                            {
                                //{"web_path", Path.DirectorySeparatorChar+Path.Combine("uploads", "__ID____EXTN__")},
                                //{"ImageID", Upload.DbType.ReadOnly},
                                {"Content", Upload.DbType.ContentBinary},
                                {"ContentType", Upload.DbType.ContentType},
                                {"Extension", Upload.DbType.Extn},
                                {"FileName", Upload.DbType.FileName},
                                {"FileSize", Upload.DbType.FileSize},
                                {"MimeType", Upload.DbType.MimeType},
                                {"CreatedDate", Upload.DbType.ReadOnly},
                                {"IsDefault", (Func<Database, IFormFile, dynamic>)((d, f) => 0)}
                            })
                            .Validator(Validation.FileSize(500000, "Max file size is 500K."))
                            .Validator(Validation.FileExtensions(new[] { "jpg", "png", "jpeg" }, "Please upload an image."))
                            )
                    )
                )
                .Debug(true)
                .Process(Request)
                .Data();
    
            var json = JsonConvert.SerializeObject(response);
            return Json(response);
        }
    }
    
    [HttpGet]
    [HttpPost]
    public ActionResult LoadImageDetails(int ProductID)
    {
        using (var db = new Database(dbType, dbConnection))
        {
            var response = new Editor(db, "Product.Images", "ImageID")
                .Model<ImageViewModel>()
                .LeftJoin("Product.ImageRef", "Product.ImageRef.ImageID", "=", "Product.Images.ImageID")
                //.LeftJoin("Product.Product", "Product.Product.ProductID", "=", "Product.ImageRef.ProductID")
                .Where("ImageRef.ProductID", ProductID)
                .Debug(true)
                .Process(Request)
                .Data();
    
            var json = JsonConvert.SerializeObject(response);
            return Json(response);
        }
    }
    
  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Here is the js

    var imageEditor;
    var imageDetailsEditor;
    
    function createChild(row) {
        var rowData = row.data();
    
        // This is the table we'll convert into a DataTable
        var table = $('<table class="table table-secondary table-hover table-striped table-bordered w-100"/>');
    
        // Display it the child row
        row.child(table).show();
    
        // Editor definition for the child table
        var imageDetailsEditor = new $.fn.dataTable.Editor({
            ajax: {
                url: "/file/LoadImageDetails",
                data: function (d) {
                    d.ProductID = rowData.ProductID;
                }
            },
            idSrc: 'Images.ImageID',
            table: table,
            fields: [
                {
                    label: 'Image ID:',
                    name: 'Images.ImageID',
                    type: "readonly"
                },
                {
                    label: 'File Name:',
                    name: 'Images.FileName'
                },
                {
                    label: 'Main Image:',
                    name: 'Images.IsDefault',
                    type: "checkbox",
                    options: [
                        { label: "", value: 1 }
                    ],
                    separator: '',
                    unselectedValue: 0
                },
                {
                    label: "Angle:",
                    name: "Images.AngleID",
                    type: "select",
                    options: [
                        { label: "", value: null },
                        { label: "Front", value: 1 },
                        { label: "Back", value: 2 },
                        { label: "Left", value: 3 },
                        { label: "Right", value: 4 },
                        { label: "Top", value: 5 },
                        { label: "Bottom", value: 6 },
                    ]
                },
                {
                    label: 'Order:',
                    name: 'Images.Importance'
                }
            ]
        });
    
        // Child row DataTable configuration, always passes the parent row's id to server
        imageDetailsTable = table.DataTable({
            dom: "Bfrtip",
            pageLength: 5,
            searching: false,
            ajax: {
                url: "/file/LoadImageDetails",
                type: "post",
                data: function (d) {
                    d.ProductID = rowData.ProductID;
                }
            },
            columns: [
                {
                    title: 'Image ID',
                    data: 'Images.ImageID'
                },
                {
                    title: 'File Name',
                    data: 'Images.FileName'
                },
                {
                    title: 'Main Image',
                    data: 'Images.IsDefault'
                },
                {
                    title: 'Angle',
                    data: 'Images.AngleID'
                },
                {
                    title: 'Order',
                    data: 'Images.Importance'
                }
            ],
            select: true,
            buttons: [
                { extend: "create", editor: imageDetailsEditor },
                { extend: "edit", editor: imageDetailsEditor },
                { extend: "remove", editor: imageDetailsEditor }
            ]
        });
    
        imageDetailsEditor.on('submitSuccess', function (e, json, data, action) {
            row.ajax.reload(function () {
                $(row.cell(row.id(true), 0).node()).click();
            });
        });
    }
    
    function updateChild(row) {
        $("table", row.child())
            .DataTable()
            .ajax.reload();
    }
    
    function destroyChild(row) {
        // Remove and destroy the DataTable in the child row
        var table = $("table", row.child());
        table.detach();
        table.DataTable().destroy();
    
        // And then hide the row
        row.child.hide();
    }
    
    
    $(document).ready(function () {
        imageEditor = new $.fn.dataTable.Editor({
            ajax: "/file/LoadAllImages",
            idSrc: 'ProductID',
            table: "#products",
            fields: [
                {
                    label: "Product ID:",
                    name: "Product.ProductID",
                    type: "readonly"
                    //type: "hidden"
                },
                {
                    label: "Part No:",
                    name: "Product.Identifier",
                    type: "readonly"
                    //type: "hidden"
                },
                {
                    label: "Title:",
                    name: "Product.Title",
                    type: "readonly"
                },
                {
                    label: "Images:",
                    name: "Images[].ImageID",
                    type: "uploadMany",
                    display:
                        function (fileId, counter) {
                            return '<img src="https://localhost:44328/UID/' + imageEditor.file('Product.Images', fileId).ImageID + imageEditor.file('Product.Images', fileId).Extension + '"/>';
                        }
                    ,
                    noFileText: 'No images',
                }
            ]
        });
    
        var productsTable = $("#products").DataTable({
            dom: "Bfrtip",
            ajax: {
                url: "/file/LoadAllImages",
                type: 'POST'
            },
            order: [1, "asc"],
            serverSide: "true",
            processing: "true",
            columns: [
                {
                    className: 'details-control',
                    orderable: false,
                    data: null,
                    defaultContent: '',
                    width: '10%'
                },
                {
                    title: 'Product ID',
                    data: "Product.ProductID"
                },
                {
                    title: 'Part No',
                    data: "Product.Identifier"
                },
                {
                    title: 'Title',
                    data: "Product.Title"
                },
                {
                    title: 'Images',
                    data: "Images",
                    render: function (d) {
                        return d.length ?
                            d.length + ' image(s)' :
                            'No image';
                    }
                }
            ],
            select: {
                style: "os",
                selector: "td:not(:first-child)"
            },
            buttons: [
                { extend: "create", editor: imageEditor },
                { extend: "edit", editor: imageEditor },
                { extend: "remove", editor: imageEditor }
            ]
        });
    
        // Add event listener for opening and closing details
        $("#products tbody").on("click", "td.details-control", function () {
            var tr = $(this).closest("tr");
            var row = productsTable.row(tr);
    
            if (row.child.isShown()) {
                // This row is already open - close it
                destroyChild(row);
                tr.removeClass("shown");
            } else {
                // Open this row
                createChild(row);
                tr.addClass("shown");
            }
        });
    
        // When updating a site label, we want to update the child table's site labels as well
        imageEditor.on("submitSuccess", function () {
            productsTable.rows().every(function () {
                if (this.child.isShown()) {
                    updateChild(this);
                }
            });
        });
    });
    

    Thanks for all your help with this. I realize this is a very complex solution I'm trying to accomplish. Hopefully this will help someone in the future as well.

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Could you show me the JSON response from the server when you trigger an edit on the child row please?

    Thanks,
    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Here is the Json for Request.Form

    [{
            "Key": "data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][ImageID]",
            "Value": ["c6000f4a-1dde-4a5f-a80a-92e4e867fdc1"]
        }, {
            "Key": "data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][FileName]",
            "Value": ["LinksUnlimited_Logo_2Color_tag.jpg"]
        }, {
            "Key": "data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][IsDefault]",
            "Value": ["1"]
        }, {
            "Key": "data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][AngleID]",
            "Value": ["5"]
        }, {
            "Key": "data[c6000f4a-1dde-4a5f-a80a-92e4e867fdc1][Images][Importance]",
            "Value": ["1"]
        }, {
            "Key": "action",
            "Value": ["edit"]
        }, {
            "Key": "ProductID",
            "Value": ["106"]
        }
    ]
    

    and here is the Json response. I have removed the actual image from "Content" due to size

    {
        "draw": null,
        "data": [{
                "DT_RowId": "row_c6000f4a-1dde-4a5f-a80a-92e4e867fdc1",
                "Images": {
                    "ImageID": "c6000f4a-1dde-4a5f-a80a-92e4e867fdc1",
                    "Content": "ActualImageContentRemoved",
                    "ContentType": "image/jpeg",
                    "Extension": ".jpg",
                    "FileName": "LinksUnlimited_Logo_2Color_tag.jpg",
                    "FileSize": 174001,
                    "MimeType": "image/jpeg",
                    "CreatedDate": "2021-10-05T12:23:55.637",
                    "IsDefault": false,
                    "AngleID": null,
                    "Importance": null
                },
                "ImageRef": {
                    "ImageID": "c6000f4a-1dde-4a5f-a80a-92e4e867fdc1",
                    "ProductId": 106
                }
            }
        ],
        "recordsTotal": null,
        "recordsFiltered": null,
        "error": null,
        "fieldErrors": [],
        "id": null,
        "meta": {},
        "options": {},
        "searchPanes": {
            "options": {}
        },
        "files": {},
        "upload": {
            "id": null
        },
        "debug": [{
                "Query": "SELECT  [Product].[Images].[ImageID] as 'Product.Images.ImageID', [Images].[ImageID] as 'Images.ImageID', [Images].[Content] as 'Images.Content', [Images].[ContentType] as 'Images.ContentType', [Images].[Extension] as 'Images.Extension', [Images].[FileName] as 'Images.FileName', [Images].[FileSize] as 'Images.FileSize', [Images].[MimeType] as 'Images.MimeType', [Images].[CreatedDate] as 'Images.CreatedDate', [Images].[IsDefault] as 'Images.IsDefault', [Images].[AngleID] as 'Images.AngleID', [Images].[Importance] as 'Images.Importance', [ImageRef].[ImageID] as 'ImageRef.ImageID', [ImageRef].[ProductId] as 'ImageRef.ProductId' FROM  [Product].[Images] LEFT JOIN [Product].[ImageRef] ON [Product].[ImageRef].[ImageID] = [Product].[Images].[ImageID] WHERE [ImageRef].[ProductID] = @where_0 AND [Product].[Images].[ImageID] = @where_1 ",
                "Bindings": [{
                        "Name": "@where_0",
                        "Value": 106,
                        "Type": null
                    }, {
                        "Name": "@where_1",
                        "Value": "c6000f4a-1dde-4a5f-a80a-92e4e867fdc1",
                        "Type": null
                    }
                ]
            }
        ],
        "cancelled": []
    }
    
  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Thank you. The JSON return there doesn't indicate that any write was done to the database at all. Are you able to give me a link to the page you are working on so I can take a look and interact with it please? You can drop me a private message by clicking my forum user name above and then Send message if you can't make it public.

    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Sent you a link in a private message. Thanks.

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Still waiting for an update on this. Have you got a chance to look at it yet?

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    I'm really sorry - I totally lost track of this one! I suspect it is to do with the schema name that is being used.

    For the child table initialisation, could you try:

    new Editor(db, "Product.Images as Images", "ImageID")
    

    And if that doesn't resolve the issue, could you show me what ImageViewModel is and I'll try to recreate the issue.

    Thanks,
    Allan

  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    Hey Allan,

    Thanks for that it's now trying to do an update. However, I'm now receiving the error "Incorrect syntax near 'Images'.". You can see in the update statement below that it's putting "Images" before the set causing the error. How can I fix this?

    UPDATE  [Product].[Images] Images SET  [AngleID] = @AngleID, [ImageID] = @ImageID, [FileName] = @FileName, [IsDefault] = @IsDefault, [Importance] = @Importance WHERE [Images].[ImageID] = @where_0
    
  • ezdavisezdavis Posts: 35Questions: 3Answers: 0

    I've went back to what I had and then added a class called "Product" in my ImageViewModel to get everything mapped correctly. Thank you for pointing me in the right direction of it being a schema issue. Here is my ImageViewModel now for anyone who may find this thread.

    public class ImageViewModel
        {
            public class Product
            {
    
                public class Images
                {
                    public System.Guid ImageID { get; set; }
                    public byte[] Content { get; set; }
                    public string ContentType { get; set; }
                    public string Extension { get; set; }
                    public string FileName { get; set; }
                    public int FileSize { get; set; }
                    public string MimeType { get; set; }
                    public DateTime CreatedDate { get; set; }
                    [EditorSet(Field.SetType.Edit)]
                    public bool IsDefault { get; set; }
                    [EditorSet(Field.SetType.Edit)]
                    public int AngleID { get; set; }
                    [EditorSet(Field.SetType.Edit)]
                    public int Importance { get; set; }
                    //public string Owner { get; set; }
                }
    
                public class ImageRef
                {
                    public System.Guid ImageID { get; set; }
    
                    public int ProductId { get; set; }
                }
            }
    
        }
    
Sign In or Register to comment.