B4J Tutorial [BANanoWebix] Lesson 22 Uploader - Method 1

Mashiane

Expert
Licensed User
Hi

We are just left with almost 2 additional widgets to complete on the standard open-source license before we can start building a working app.

The uploader widget enables one to upload files. There are a various ways this works and we will now look at Method 1. We use this and we link it to a grid element.

We will create a data-table with an image, when a user clicks the image, a file dialog will appear prompting the user of the image file to select, when that is complete we attempt to upload the file to the server.

Lesson22.1.gif


1. We create our page with a spacer layout (notice the padding around the elements)

B4X:
pg.Initialize("").SetHeader("Lesson 22: File Uploader - Part 1")
    pg.Page.SetTypeSpace
2. We create a few rows and also the HTML template for our images to be shown on the data-table.

B4X:
Dim R1 As WixRow
    R1.Initialize("R1").SetTemplate("<p>Click on any photo to change it</p>").SetHeight(50)
    pg.AddRow(R1)
    '
    Dim R2 As WixRow
    R2.Initialize("R2")
    '
    Dim sPhoto As String
    Dim img As UOENowHTML
    'create the template to show the image
    img.Initialize("img", "img").SetStyle("cursor", "pointer").SetStyle("width", "80px").SetStyle("height", "80px").SetSRC("./assets/#photo#",True)
    sPhoto = img.HTML
The result of this image template is...

B4X:
<img id='img' src='./assets/#photo#' style='cursor:pointer !important; width:80px !important; height:80px !important;' >
What this means is that for that particular column, use the data stored in the 'photo' key and display it within an 'img' tag.

3. We then create a data-table and then add columns to it and set the data to display. We have saved some image pngs on our assets folder of the app.

B4X:
Dim dt As WixDataTable
    dt.Initialize("people")
    dt.CreateHeader("photo").SetHeader(" ").SetWidth(100).SetTemplate(sPhoto).Pop2(dt)
    dt.CreateHeader("name").SetHeader("Employee Name").SetWidth(200).Pop2(dt)
    dt.CreateHeader("job").SetHeader("Job Title").SetFillSpace(True).Pop2(dt)
    dt.Setautoheight(True).SetscrollX(False).SetRowHeight(80)
    '
    Dim data As List
    data.Initialize
    data.Add(CreateMap("id":1, "name":"Alex Bret", "job":"Manager", "photo":"2.png"))
    data.Add(CreateMap("id":2, "name":"Ruby Goldberg", "job":"Lead developer", "photo":"1.png"))
    dt.SetData(data)
  
    '
    R2.AddItem(dt.Item)
    '
    pg.AddRow(R2)
    pg.ui
4. We want whenever a user selects the image, a file dialog should appear, then we add an itemClick method to the grid.

B4X:
'add a click event per row
    Dim row As Map
    pg.onitemclick("people", BANano.CallBack(Me,"itemClick",Array(row)))
  
    ' create an uploader and add it to the page in run-time
    Dim upload As WixUploader
    upload.Initialize("upload").SetUpload("./assets/upload.php").SetName("uploader").SetApiOnly(True)
    upload.SetAccept("image/png, image/gif, image/jpeg")
    '
    fu = pg.AddUploader(upload)
When a row is clicked, the itemClick sub will be called. This activates the WixUploader class we created named 'upload' which was added to the page with .AddUploader. This is a run-time created component (Method 1)

B4X:
Sub itemClick(row As Map)
    Dim rid As String = row.Get("row")
    Dim col As String = row.Get("column")
    rid = pg.CStr(rid)
    col = pg.CStr(col)
  
    Select Case col
    Case "photo"
        'when a photo is selected, show file dialog
        pg.FileDialog("upload", CreateMap("rowid": rid))
    End Select
End Sub
5. The uploader accepts the script to load to upload. One can also indicate the types of files it needs to accept. For this example we are accepting images.

We will look deeper into the 'upload.php' script later.
 
Last edited:

Mashiane

Expert
Licensed User
The Upload.PHP script

Our upload.php script being pointed is supposed to save the file on the assets folder of our server and then when that is done, show the new image on the data-table

B4X:
<?php
header("Access-Control-Allow-Origin: *");
ini_set('max_execution_time',120);
if (isset($_FILES['upload'])) {
    // Example:
    if(move_uploaded_file($_FILES['upload']['tmp_name'], "../assets/" . $_FILES['upload']['name'])){
        echo '{ "status": "success" }';
    } else {
        echo '{ "status": "error" }';
    }
    exit;
} else {
    echo '{ "status": "error" }';
}
?>
We save this file on our 'Files' tab in our project.

For this to be possible, we need to trap the onFileUpload and the onFileUploadError of our uploader widget. We attach these events easily.

B4X:
Dim ffile As BANanoObject
    pg.OnFileUploadError("upload", BANano.CallBack(Me, "onFileUploadError", Array(ffile)))
    pg.onFileUpload("upload", BANano.CallBack(Me, "onFileUpload", Array(ffile)))
The onFileUpload event, returns a file object that we can manipulate (as per console log)

B4X:
Object
context: {rowid: "1"}
file: File
lastModified: 1561990069925
lastModifiedDate: Mon Jul 01 2019 16:07:49 GMT+0200 (South Africa Standard Time) {}
name: "mashy.png"
size: 28695
type: "image/png"
webkitRelativePath: ""
__proto__: File
id: 1561990114028
name: "mashy.png"
percent: 100
progress: 100
size: 28695
sizetext: "28.02 Kb"
status: "success"
type: "png"
__proto__: Object
The methods to run on the events. The status of the upload will be 'success' if the file was uploaded or 'error' if there was an error.

B4X:
Sub onFileUpload(ffile As BANanoObject)
    Log("onFileUpload")
    'get the status
    Log(ffile)
    Dim status As String = ffile.GetField("status").Result
    Select Case status
    Case "success"
        'get the row id
        Dim rowid As String = pg.GetRowIDFromContext(ffile)
        'get the row object from data-table
        Dim row As Map = pg.GetItem("people", rowid)
        'get the file name
        Dim fname As String = ffile.GetField("name").Result
        'update the row photo
        row.Put("photo", fname)
        'update the data-table
        pg.UpdateItem("people", rowid, row)
    Case Else
        pg.Alert("Error during file upload!")
    End Select
End Sub


Sub OnFileUploadError(ffile As BANanoObject)
    Log("OnFileUploadError")
    Log(ffile)
    pg.Alert("Error during file upload!")
End Sub
Here, the uploader is invisible and is linked to the user image. When the image is clicked, a file dialog is provided. Once the user selects an image, the file is loaded to the server and displayed. So we get the returned 'context' of the uploader i.e. the row. We get the rowid, from the rowid, get the row map from the grid, we read the file name from the uploaded file and then assign this to the 'photo' property which is used in the template '#photo#', as soon as we update the row for that image, the image is shown automatically.
 
Top