Kendo dropdown inside upload template not rendering after the first one

3 Answers 420 Views
Upload
Rey
Top achievements
Rank 2
Iron
Iron
Rey asked on 29 Mar 2022, 03:23 PM

I am inserting a kendo dropdown control inside an upload template so that the user can select a document type for each file uploaded.  The upload control allows multiple files, it is not async.  It works the first time but subsequent files do not render the dropdown, only a text box instead of a dropdown list.

Here's my razor code:


        <div>
            @(Html.Kendo().Upload().Name("upload")
                .Multiple(true)
                .TemplateId("UploadTemplate"))
        </div>

Here's my template:


<script id="UploadTemplate" type="text/x-kendo-template">
    <span class='k-progress'></span>
            <div><label>Name:</label>#=name#</div>
            <div><label for='NewDoc_Type_DocumentTypeId'>Document Type:</label>
                @(Html.Kendo().DropDownList()
                    .Name("NewDoc.Type.DocumentTypeId")
                    .HtmlAttributes(new { name = "NewDoc.Type.DocumentTypeId", style = "width: 260px;" })
                    .BindTo(DocumentTypes())
                    .DataTextField("DocumentTypeText")
                    .DataValueField("DocumentTypeId")
                    .Events(e => e.Select("TypeSelected")).ToClientTemplate()
                )
            </div>
        <div style='display: none;' id='divTypeOther'>
            <label for='NewDoc_TypeOther'>Document Type - Other: </label>
            <input type='text' name='NewDoc.TypeOther' id='NewDoc_TypeOther' />
        </div>
</script>

Also, I want to show a text box of "Other" when the user selects "OTHER" from the dropdown.  Again, it works on the first one but the ids are the same starting with the second one so it wouldn't work.

3 Answers, 1 is accepted

Sort by
0
Yanislav
Telerik team
answered on 01 Apr 2022, 11:18 AM

Hello Reynaldo,

In order to display the Drop Down Lists properly from the template, you should declare a different Name() configuration for each Drop Down List. In order to do so, I recommend you a similar approach to the following one : 

1. Hook up for the Select event of the Upload : 

.Events(ev=>ev.Select("onUploadSelect"))

2. Declare a global variable and increment its value when the handler of the Select event is fired :

    var counter = 1;
    function onUploadSelect() {
        counter++;
    }

3. By using the Kendo Template syntax, use this variable to generate a unique name for the DropDownList within the template :

    @(Html.Kendo().DropDownList()
        .Name("#=counter#")
        .Events(ev=>ev.Select("onDropDownSelect"))
        .BindTo(new string[] { "One", "Other"}).ToClientTemplate()
    )

This way each time a file is selected for upload the value of the variable - "counter" would be different and the DropDownLists should have different names and render properly.

Regarding your other requirement, in other to replace the DropDownList based on the selection, I recommend you to hook for the Select event of the DropDownList :

.Events(ev=>ev.Select("onDropDownSelect"))

And within the handler to destroy the DropDownList and replace the content of its container with a text box :

    function onDropDownSelect(e) {
        if (e.dataItem == "Other") {
            var id = $(e.sender.element).attr('id');
            $('#' + id).data('kendoDropDownList').destroy()
            var file = $('#' + id).closest('.k-file');
            file.empty()
            file.append('<input type="text" class="k-input" />');
        }
    }

I hope this information is helpful and that the suggestion will help you to reach the desired aim.

Regards,
Yanislav
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Rey
Top achievements
Rank 2
Iron
Iron
answered on 05 Apr 2022, 07:59 PM

Hi Yanislav,

Thanks for the reply.  I made it work with the example that you provided but I cannot hide the dropdown list, I need to keep it visible so I modified the code and made it work.

Here's my code:

    function TypeSelected(e) {
        var id = $(e.sender.element).attr("id");
        var file = $("#" + id).closest(".k-file");
        var divOther = file.find(".divTypeOther");

        if (e.dataItem.DocumentTypeText == "OTHER") {
            divOther.show();
        } else {
            divOther.hide();
        }
    }

Now there's two issues. 

  1. When upload is multiple, it allows to select more than one file on the dialog box but the line shows only one dropdown (see screenshot).  If multiple is false so that user can select only one file, it overwrites the file after the second selection.  I want so that if the user selects more than one file, it adds the same amount of lines with their respective dropdown.
  2. On the controller, I get the list of files but only the first dropdown value for all the files, I need to get one dropdown value per file.  How do I do that?

 

Yanislav
Telerik team
commented on 08 Apr 2022, 10:26 AM

Hello Reynaldo,

Let me address your questions below :

1. In order to display the template for each selected file, I recommend you to use Async uploading. Here is an example : 
https://netcorerepl.telerik.com/wQYoEiFu01R4foKr01

2. About your second requirement, unfortunately, there is no such functionality exposed, since the DropDownList has no information about the files. So in order to send additional information on the server, there should be some kind of relation between the DropDownList and the respective file. You could try to set an attribute of the DropDownList by using the HtmlAttributes() method that should contain the name of the file to which this DropDownList refers.
This could be done by saving the currently selected files in a global JS array :

    var files = [];
    function onSelect(e) {
        files = e.files;
    }

Within the template, by using the Kendo Template syntax, set the name of the widget to match the filename : 

    # counter++ #
    # var file = files.pop() #
    # console.log(file) #
    @(Html.Kendo().DropDownList()
        .Name("#=counter#")
        .Events(ev=>ev.Select("onDropDownSelect"))
        .HtmlAttributes(new { name="#=file.name#"})
        .BindTo(new string[] { "One", "Other"}).ToClientTemplate()
    )

This way when sending the data by using the name of the file, you could refer to the DropDownList, and get its value.

I hope this helps!

 

0
Rey
Top achievements
Rank 2
Iron
Iron
answered on 12 Apr 2022, 12:28 PM

Hi Yanislav,

The template works, I get all the dropdowns and the change events work.  But... How do I get the dropdown value?   I've tried different things without success.  Also, I cannot get the value to the controller, the variable "doc" is null.  I put code in my upload event but how do I get the value of the dropdown?  The variable "e" doesn't have any information on the file, the e.files[] length is zero.  How do I use the global files[] variable?  Am I doing something wrong?

Upload control:

@(Html.Kendo().Upload().Name("uploads")
	.Multiple(true)
	.Async(a => a
		.Save("Document_Upload")
		.Remove("Document_Remove")
		.AutoUpload(false)
	)
	.TemplateId("UploadTemplate")
	.Events(e => e
		.Select("onFileSelect")
		.Upload("onUpload")
	))

JavaScript:

var fileCounter = 0;
var files = [];

function onUpload(e) {
	var DocModel = {
		CaseNumber: "1",
		DocumentType: $("input[name='" + <????>+ "']").data("kendoDropDownList").value()
	}

	e.data = { doc: DocModel };
}

function onFileSelect(e) {
	files = e.files;
}

Template:

<script id="UploadTemplate" type="text/x-kendo-template">
    # fileCounter++ #
    # var file = files.pop() #
        <span class='k-progress'></span>
            <div><label>Name:</label>#=name#</div>
            <div><label>Document Type:</label>
                @(Html.Kendo().DropDownList()
                    .Name("#=fileCounter#")
                    .HtmlAttributes(new { name = "#=file.name#", style = "width: 260px;" })
                    .BindTo(GetDocumentTypes())
                    .DataTextField("DocumentTypeText")
                    .DataValueField("DocumentTypeId")
                    .ToClientTemplate()
                )
            </div>
</script>

Controller:

 public ActionResult Document_Upload(DocumentModel doc, IEnumerable<HttpPostedFileBase> uploads)
{
	string msg = "";

	if (uploads == null)
	{
		msg = "File missing.  Please select a file(s) from your computer.");
	}
	else
	{   
		foreach (var file in uploads)
		{
			if (file == null)
			{
				msg = "File is missing.";
			}
			else
			{	
                               //set up values using doc variable & upload
				var fileName = Path.GetFileName(file.FileName);
				var savePath = "\\Upload\\" + fileName;
				//file.SaveAs(savePath);
			}
		}
		
	}

	return Content(msg);
}

Eyup
Telerik team
commented on 15 Apr 2022, 08:28 AM

Hi


Tags
Upload
Asked by
Rey
Top achievements
Rank 2
Iron
Iron
Answers by
Yanislav
Telerik team
Rey
Top achievements
Rank 2
Iron
Iron
Share this question
or