Unable to load up an image from an Action due to property access

1 Answer 35 Views
Avatar Grid
DoomerDGR8
Top achievements
Rank 2
Iron
Iron
Iron
DoomerDGR8 asked on 11 Dec 2023, 03:58 PM

Here is my grid:

@(Html.Kendo().Grid<AssetViewModel>()
      .Name("grid")
      .Columns(columns =>
       {
           columns.Bound(e => e.AssetId).Title("Asset").ClientTemplate(Html.Kendo().Template().AddComponent(avatar => avatar
                                                                                                                     .Avatar()
                                                                                                                     .Name("avatar_${data.AssetId}")
                                                                                                                     .Type(AvatarType.Image)
                                                                                                                     .Size(ComponentSize.Large)
                                                                                                                     .Rounded(Rounded.Full)
                                                                                                                     .Image(@Url.Action("GetFile", "MediaStore", new { fileId = "${data.LogoId}" }))
                                                                                                           )).Width(110);
           columns.Bound(e => e.AssetName).Title("Full Name").Width(200);
       })
      .Sortable()
      .Pageable()
      .Scrollable()
      .HtmlAttributes(new { style = "height:430px;" })
      .DataSource(dataSource => dataSource
                               .Ajax()
                               .PageSize(5)
                               .Read(read => read.Action("AssetListData", "Revenue"))
                 )

)

I have tried specifying as "#:AssetId#", "#=AssetId#" , and ${data.LogoId} but the parsing is not correct at runtime:

<span class="k-avatar-image"><img src="/MediaStore/GetFile?fileId=$%7Bdata.AssetId%7D"></span>

Ho do I get the LogoId properly?

1 Answer, 1 is accepted

Sort by
1
Alexander
Telerik team
answered on 14 Dec 2023, 11:10 AM

Hi Hassan,

The reported behavior would most notably be related to an identical symptom, as discussed in a previous discussion of ours:

Forum Post - https://www.telerik.com/forums/a-tabstrip-as-a-clientdetailtemplate

With that in mind to achieve the desired outcome, I would recommend:

  • Subscribing to the DataBound event of the Grid:
.Events(events => events.DataBound("onDataBound"))
  • Omit the Image() API configuration of the Avatar in the Template declaration:
.Columns(columns =>
{

    columns.Bound(e => e.ShipCity).Title("Asset").ClientTemplate(Html.Kendo().Template().AddComponent(avatar => avatar
           .Avatar()
           .Name("avatar_${data.Id}")
           .Type(AvatarType.Image)
           .Size(ComponentSize.Large)
           .Rounded(Rounded.Full)
	)).Width(110);

})
  • Within the DataBound handler, traverse through each of the row DOM representations, get the respective dataItem, recompose the URL, so that the query string is included, and re-render the Avatar by using its exposed setOptions() method:
<script>
    function onDataBound(e) {
        setTimeout(function(){

            $(e.sender.element).find(".k-master-row").each((index, el) => {
                var dataItem = e.sender.dataItem(el);
                var avatar = $(el).find(`.k-avatar`).data("kendoAvatar");


                avatar.setOptions({
                    image: `MediaStore/GetFile?fileId=${dataItem.Id % 2 == 0 ? 1 : 2}`
                })

            })

        }, 200)
    }
</script>

This should then supplement the query string for each of the rows accordingly in the request URL:

Whilst ensuring that the images are displayed:

For your convenience, I am attaching a revamped version of the sample from the abovementioned discussion. 

I hope this helps.

Kind Regards,
Alexander
Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages. If you're new to the Telerik family, be sure to check out our getting started resources, as well as the only REPL playground for creating, saving, running, and sharing server-side code.
DoomerDGR8
Top achievements
Rank 2
Iron
Iron
Iron
commented on 15 Dec 2023, 09:23 PM

Thanks. This is almost everything I need.

  • The path needed a forward slash as it was looking for a MediaStore/GetFile inside the current controller.
  • If the ProfileId is null (lots of existing records and the ProfilepictureId was added later as nullable) the code breaks strangely:

I tried a few remedies. On the controller, I updated as:


[HttpGet]
public async Task<IActionResult> GetFile(Guid? fileId, int? typeId)
{
    var ct = new CancellationToken();

    try
    {
        if (fileId == null || fileId == Guid.Empty)
        {
	        var filePath = Path.Combine(hostEnvironment.WebRootPath, typeId == 2 ? "img/user/user-12.jpg" : "img/default/blank.jpg");
	        var fileBytes = await System.IO.File.ReadAllBytesAsync(filePath, ct);

	        return File(fileBytes, "image/jpeg");
        }

        var viewModel = await mediaService.GetFileAsync(fileId.Value, ct);

        if (viewModel == null)
        {
            return NotFound("File not found.");
        }

        var fileData = await mediaService.GetFileDataAsync(fileId.Value, ct);

        return new FileContentResult(fileData, "application/octet-stream")
               {
                   FileDownloadName = viewModel.Name
               };
    }
    catch (Exception ex)
    {
        return Json(new { success = false, message = ex.Message });
    }
}


The onDataBound is modified as:


function investorGrid_OnDataBound(e) {
    try {
        setTimeout(function() {
            $(e.sender.element).find(".k-master-row").each((index, el) => {
                var dataItem = e.sender.dataItem(el);
                var avatar = $(el).find(".k-avatar").data("kendoAvatar");

                if (dataItem.ProfilePictureId) {
                    avatar.setOptions({
                        image: `/MediaStore/GetFile?fileId=${dataItem.ProfilePictureId}&typeId=2`
                    });
                } else {
                    avatar.setOptions({
                        image: ''
                    });
                }
            });
        }, 200);
    } catch (e) {

    }
}

However, this is not working still:

How do I tackle this?

 

Alexander
Telerik team
commented on 20 Dec 2023, 01:03 PM

Hi Hassan,

Thank you for the additional clarification regarding the backslash behavior.

In terms of the scenario where the "ProfilePictureId" will be treated as times as nullable, I would personally recommend adding a default image that will be displayed when the profile picture is uploaded.

This would be required due to the fact that the image configuration will point to a URL. In the case of null entries, it will try to compose a URL where "null" will be taken purely as textual content.

Here is how I have altered the implementation:

<script>
    function onDataBound(e) {
        setTimeout(function(){

            $(e.sender.element).find(".k-master-row").each((index, el) => {
                var dataItem = e.sender.dataItem(el);
                var avatar = $(el).find(`.k-avatar`).data("kendoAvatar");


                if (dataItem.ProfilePictureId) {
                    avatar.setOptions({
                        image: `/MediaStore/GetFile?fileId=${dataItem.ProfilePictureId % 2 == 0 ? 1 : 2}`
                    })
                } else {
                    avatar.setOptions({
                        image: '@Url.Content("~/no_image.png")'
                    });
                }
            })

        }, 200)
    }
</script>

Where the default image is stored as follows:

This will then produce the following result:

Attached you will find a revised version of the previous sample for you to review.

I hope this helps.

Tags
Avatar Grid
Asked by
DoomerDGR8
Top achievements
Rank 2
Iron
Iron
Iron
Answers by
Alexander
Telerik team
Share this question
or