ShowURL downloading question

I have a WebPage with a ListBox. I have no problems allowing the user to download a single row’s data with code like this:

[code]Dim s As String = […]
Dim CSVFilename As String = […]

Self.TextFile = New WebFile
Self.TextFile.MimeType = “text/plain”
Self.TextFile.ForceDownload = True
Self.TextFile.FileName = CSVFilename
Self.TextFile.Data = s

ShowURL(Self.TextFile.URL)[/code]

That works great. TextFile is a property (As WebFile) of the Web page that contains the method. But if I want to allow the user to download a CSV file for each row in one fell swoop (producing a series of files), I find that only the last row gets downloaded to a file, where I use code like this:

If MyWebListBox.RowCount > 0 Then For row As Integer = 0 To MyWebListBox.RowCount - 1 [...run the earlier code, accounting for each change in row...] Next End If

It appears that the ShowURL(Self.TextFile.URL) step only executes at the end of the final iteration.

It is too bad that you don’t post the exact code you use to get the whole listbox content.

Do you correctly concatenate each row, with endOfLine at each end, so s contains not only one row, but all rows ?

Michel,

I thought it would overkill to post the method that creates the CSV file, since it works fine when not run inside the loop. That is, it successfully downloads a single CSV file from the row that calls it via the DoubleClick event. I just have a problem when it is run inside the loop that attempts to download a series of CSV files based on all the rows seen in the displayed WebListBox. In that case, after running through all the rows in the loop, it ends up successfully executing the ShowURL(Self.TextFile.URL) step only during the last iteration.

Anyway, here’s the code in full, with some extra comments added for this post:

[code]// Method name: DownloadAllCSVs
// This method attempts to download all the CSVs for the selected agent.
// It runs the SaveToCSV method that you see after it here, in a loop
// that covers all rows found in the displayed WebListBox (AgentWeeksList1).
// SaveToCSV takes 5 parameters (agentID, agentWebID, year, week and agentName).
// SelectedAgentID, SelectedAgentWebID and SelectedAgentName are properties of the WebPage.
// The year and week strings are found in cells 0 and 1, respectively.

If AgentWeeksList1.RowCount > 0 Then
For row As Integer = 0 To AgentWeeksList1.RowCount - 1
Self.SaveToCSV(_
AdminAgentsPage.SelectedAgentID, _
AdminAgentsPage.SelectedAgentWebID, _
AgentWeeksList1.Cell(row, 0), _
AgentWeeksList1.Cell(row, 1), _
AdminAgentsPage.SelectedAgentName _
)
Next
Else
Return
End If[/code]

[code]// Method name: SaveToCSV
// Parameters passed, all as strings: year, week, agentID, agentWebID, agentName.
// AccountabilityFieldsNames_Week_CSV is a list of field names for the header row.

// Set the CSVFilename filename
Dim CSVFilename As String = _
“WeeklyData-” + year + “-” + week + “-” + _
agentID + “-” + ReplaceAll(agentName, " ", “”) + _
“.csv”

// Setup variables for writing the two rows (header and data).
Dim i As Integer
Dim names() As String = AccountabilityFieldsNames_Week_CSV
Dim line1 As String
Dim line2 As String
Dim s As String

// Write header row.
For i = 0 To Ubound(names)
If i <> Ubound(names) Then
line1 = line1 + names(i) + “,”
Else
line1 = line1 + names(i)
End If
Next
s = line1

// Get data from database file to be used for data row.
Dim sql As String
Dim rs As RecordSet
sql = “SELECT * FROM AgentWeeks” + _
" WHERE AgentWebID = " + agentWebID + _
" AND Year = " + year + _
" AND Week = " + week
rs = Session.DB.SQLSelect(sql)

// ***
// Error logging goes here, which I omitted for this post
// ***

// Write data row.
For i = 0 To Ubound(names)
If i <> Ubound(names) Then
line2 = line2 + Str(rs.Field(names(i)).IntegerValue) + “,”
Else
line2 = line2 + Str(rs.Field(names(i)).IntegerValue)
End If
Next
s = s + EndOfLine + line2

// Prepare the file for download.
Self.TextFile = New WebFile
Self.TextFile.MimeType = “text/plain”
Self.TextFile.ForceDownload = True
Self.TextFile.FileName = CSVFilename
Self.TextFile.Data = s

// Download the file.
ShowURL(Self.TextFile.URL)[/code]

I even did a test, where I made the loop do only one interation, and it worked fine:

If AgentWeeksList1.RowCount > 0 Then For row As Integer = 0 To 0 Self.SaveToCSV(_ AdminAgentsPage.SelectedAgentID, _ AdminAgentsPage.SelectedAgentWebID, _ AgentWeeksList1.Cell(row, 0), _ AgentWeeksList1.Cell(row, 1), _ AdminAgentsPage.SelectedAgentName _ ) Next Else Return End If

But increasing the iterations to 2 resulted in the ShowURL step running only on the second iteration:

If AgentWeeksList1.RowCount > 0 Then For row As Integer = 0 To 1 Self.SaveToCSV(_ AdminAgentsPage.SelectedAgentID, _ AdminAgentsPage.SelectedAgentWebID, _ AgentWeeksList1.Cell(row, 0), _ AgentWeeksList1.Cell(row, 1), _ AdminAgentsPage.SelectedAgentName _ ) Next Else Return End If

What is in SaveToCSV ?

What you describe looks like instead of concatenating the rows, you just use the last one to write.

I posted 2 methods in my first reply to you: DownloadAllCSVs and SaveToCSV. The first calls the second. Perhaps it looked like a single method. I should have put some space between the two code frames in that reply.

The first method attempts to download a series of CSV files. The second method creates each CSV file.

Here’s a simple Web project I just created to show this problem. It attempts to create and download 2 text files, but only succeeds in downloading the second one when ShowURL is used:

https://www.dropbox.com/s/9f06c86sy7mcjpd/testShowURL.xojo_binary_project?dl=1

I imagine I have to do this with an array TextFile() as WebFile.

Ok, I have tested this with a very simple Web project and find that only 1 file can be downloaded using a WebFile in a method, and it will always be the last one built. Even if I use two different properties on the WebPage that are WebFiles (TextFile1 and TextFile2), the following method will download only the 2nd file:

[code]// Prepare 1st file for download.
Self.TextFile1 = New WebFile
Self.TextFile1.MimeType = “text/plain”
Self.TextFile1.ForceDownload = True
Self.TextFile1.FileName = “file1”
Self.TextFile1.Data = “abc”

// Prepare 2nd file for download.
Self.TextFile2 = New WebFile
Self.TextFile2.MimeType = “text/plain”
Self.TextFile2.ForceDownload = True
Self.TextFile2.FileName = “file2”
Self.TextFile2.Data = “def”

// Download 1st file.
ShowURL(Self.TextFile1.URL)

// Download 2nd file.
ShowURL(Self.TextFile2.URL)[/code]

Hey Ralph…

Maybe you need to run that code in a Timer that starts the second file download when the first one is finished?

I would create a download queue, and use the WebFile.Downloaded event to know when to start the next download.

Michel,

Is a download queue created using a Timer, as Hal suggests?

No need for a timer, I believe.

In a simple folderItems array, just load the files to showURL.
Add a myWebFile as WebFile property to the webPage

Then it should work by :

  • fetch a new folderItem to showURL
  • Create a WebFile with it : myWebFile = Webfile.Open()
  • ShowURL
  • Wait until WebFile.Downloaded happens
  • Start over with the next folderItem

[quote=324976:@Michel Bujardet]No need for a timer, I believe.

In a simple folderItems array, just load the files to showURL.
Add a myWebFile as WebFile property to the webPage

Then it should work by :

  • fetch a new folderItem to showURL
  • Create a WebFile with it : myWebFile = Webfile.Open()
  • ShowURL
  • Wait until WebFile.Downloaded happens
  • Start over with the next folderItem[/quote]

Okay, I finally got this. I was having trouble getting my mind around how to Wait for each download to occur. After doing some looking at the Downloading Files example app, I finally see that I can use the WebFile.Downloaded Event Handler for the WebFile for this, which I finally realized is what Michel is referring to above. At first I thought Michel was referring to the WebFile.Download Method, and just mistyped it above. Now I see he was referring to the WebFile Event Handler, not Method, and that inherently lets me Wait for that event to occur before moving on to the next file. Now I can use all the steps Michel outlined to accomplish what I want.