l

POSTED ON Thursday 31 October 2024

In my recent project, I encountered a complex issue while implementing a file download feature for a document management system. The file download process required integration between an AngularJS frontend and a Java Spring Boot backend, with files stored dynamically on the server.


Outcome, when a link/button is clicked, it able to auto download inside local pc & able to successfully open the downloaded file:

Challenges:

When attempting to download files, I encountered various issues:

1. File Not Downloading Properly: Initial attempts to download files led to corrupted or unopenable files.

2. Dynamic Path Handling: The backend stored files in a specific directory, requiring a way to build the correct URL dynamically from AngularJS.

3. Browser Compatibility & Blob Usage: Some methods for file downloading worked inconsistently across browsers or introduced compatibility issues.

4. Need to follow a standardized Angular JS' $resource for making the backend calls to fetch files while dynamically building the download URL.


Solution:

1. Dynamic File Path Resolution in Java: I configured the Java backend to handle file paths using

Path filePath = Paths.get("path/directory").resolve(filename).normalize();

This allowed the backend to access files from a specified directory dynamically based on user input.

2. AngularJS Fetching with $resource: Instead of using direct $http requests, I utilized $resource for consistency with other service calls, allowing smoother data fetching and handling response data more flexibly.

> What I mean by this is, this project has standardized to call the fetch API method using a service called FormService when it utilizes the Angular's $resource:

angular.module('app').factory('FormService', ['$resource', function($resource, $routeParams) {

    //http://localhost:9090/api/../../..

    var uparams = {modulecode: '@modulecode',caseid: '@caseid', version: '@version', p:'@p', action: '@action', id: '@id', mode: '@mode', process: '@process', taskid: '@taskid', filename: '@filename', filter: '@filter', type: '@type', module: '@module'}

return $resource(':url', uparams, { 


Then inside the $resouce, i return the function:
    downloadLetterFile : {
                method: 'GET',
                url: '/apps/api/docs/:filename',
                responseType: 'arraybuffer'
            },

This function is then called inside the Angular controller as I have describe in step part no.3 below. 

3. Frontend Download Handling: I set up a fetch API fallback, along with AngularJS $resource functions, to handle the file download with checks for response validity and cross-browser compatibility.

> It involves with an HTML <a> element to trigger the download, allowing me to handle the download dynamically and with minimal compatibility issues. Here's the example of how I've implemented this:

$scope.downloadFile = function(letterfilename) {

    if (!letterfilename) {

        ciWarn("", "No filename provided for download.");

        return;

    }


    // Define the download URL based on backend path and filename

    const downloadUrl = $scope.baseUrl + '/api/docs/' + encodeURIComponent(letterfilename);


    // Call FormService to fetch the file using $resource

    FormService.downloadLetterFile({ filename: letterfilename }, function(response) {

        if (response) {

            // Create a temporary <a> element to trigger the download

            const link = document.createElement('a');

            link.href = downloadUrl;  // Set the URL for the file

            link.download = letterfilename;  // Set the download attribute for filename

            document.body.appendChild(link); // Append to DOM temporarily

            link.click();  // Trigger download

            document.body.removeChild(link); // Clean up by removing the link

        } else {

            ciWarn("", "File not found on the server.");

        }

    }, function(error) {

        console.error("Error downloading file:", error);

        ciWarn("", "Unable to download file due to a network error.");

    });

};



0 Comment(s)


POSTED ON Tuesday 8 June 2021

The tags introduced in HTML5 are more descriptive such as:

main, header, footer, nav, video, article, section, audio & many more. 

These tags helps with Search Engine Optimization (SEO) and accessibility. The main tag helps search engine and other developers find the main content of your page. 

Adding an image to your page:

  • Using img element by pointing it to a specific image's URL using the src attribute. This img tag is self-closing. The img tag must come with alt attribute to help screen readers especially when the image is failed to load (might be due to heavy load, internet connection and whatnots). alt attribute should contain a description of the image to help screen readers understand it.

Link to external pages:

  • Using a (anchor) element to link to any external pages
  • The a tag contains href attribute which contains the destination page's URL
  • The tag should also contain anchor text to allow clickable text which will direct user to the destination page
  • </a> is the closing tag
Link to internal sections within the page:
  • Using the same anchor element as explained above
  • However, the assigned link's href attribute need to include a hash symbol # followed by the value of the id attribute for the intended element
To open the link in a new tab:
  • Add the following code: target="_blank" after the href attribute


0 Comment(s)


POSTED ON Monday 7 June 2021

Here's for a bunch of ideas: https://what-to-code.com/?order=POPULAR


0 Comment(s)


POSTED ON Thursday 3 June 2021

 1. Connect Web Worker to SQL Database. Web worker does not allow default JQUERY to be used. Alternatives:

  • There's another alternative such as fake DOM JQUERY & importScripts() method (but unfortunately, this alternate method doesn't work for me - there were still some errors)
  • Use fetch method:
fetch('process.php').then(res => res.text())    //convert the above data (from the url) into text
                .then(body =>{
                    self.postMessage(body);
                })

2. Print all data from SQL database:
After you have successfully connected to the PHP file (read no.1), you can continue step 2 which is to print all the data from the database by using for loop.

 // if result is not zero, display result
 if($result-> rowCount() > 0){
    for($i = 0; $i < $result->rowCount(); $i++){
        $row = $result-> fetch(PDO::FETCH_ASSOC);
        print_r(json_encode($row));
        // echo $row["user_email"] .="\n";
    }
}

*notes: print_r(json_encode($row)); actually print the data in encoded json format. You've to include it in the for loop, otherwise it will only print the first OR last data fetched.



0 Comment(s)


POSTED ON Saturday 29 May 2021

1. Please refer to this post to display data in table

2. After displaying them in the table, follow the instructions attached on the comment section (//):

 //determine no of data to display per page

$results_per_page = 10;

//count all column from the database

$sql = "SELECT COUNT(*) FROM test_user";

$res = $dbx->query($sql);

$count = $res->fetchColumn();


// determine no of total pagination needed by dividing no of total columns ($count) with total data to display (10)

$number_of_pages = ceil($count/$results_per_page);


// determine which page number visitor is currently on

if(!isset($_GET['page'])){

    $page = 1;

}else{

    $page = $_GET['page'];

}


// determine the sql LIMIT starting number for the results on the displaying page

$this_page_first_result = ($page-1)*$results_per_page;

                        

$sql = "SELECT id, user_email, user_fullname, user_address, user_city, user_zip, user_state, user_country, user_tel, user_fax from test_user LIMIT ". $this_page_first_result . "," .$results_per_page;

$result = $dbx->query($sql);


// if result is not zero, display result

if($result-> rowCount() > 0){

while($row = $result-> fetch(PDO::FETCH_ASSOC)){

echo "<tr><td>".$row["id"]."</td><td>"

.$row["user_email"] . "</td><td>"

.$row["user_fullname"]."</td><td>"

.$row["user_address"]."</td><td>"

.$row["user_city"]."</td><td>"

.$row["user_zip"]."</td><td>"

.$row["user_state"]."</td><td>"

.$row["user_country"]."</td><td>"

.$row["user_tel"]."</td><td>"

.$row["user_fax"]."</td></tr>";

}

  echo "</table>";

}

// if result is zero, display 0 result

else{

 echo "0 result";

}

// loop: define $page = 1, as long as $page less or equal to $number_of_pages, increase $page ((in this case, it is: 1,2,3))

// in the loop, echo the pagination style you want to display. in this case, I use the one in Bootstrap 5 Pagination

for($page=1; $page<=$number_of_pages; $page++){

    echo '<ul class="pagination pagination-sm">

    <li>

    <span class="page-link"><a href="display-data.php?page='. $page. '">' . $page. '</a></span>

     </li>';

                            

}


0 Comment(s)


POSTED ON

The above picture refers to the table displaying the information from an SQL database.

*note: this tutorial is using Bootstrap 5 (CSS Framework) & PDO (PHP Data Object)


1. Set connection to the database
<?php
require_once('core.php')
?>

2. Write HTML <table>

    <div class="data">
    
        <div class="row">
            <div class="col-lg-12">
                <div class="table-responsive">
                    <table class="table table-striped table-hover">
                    <thead>
                    <tr>
                        <th scope="col">ID</th>
                        <th scope="col">Email</th>
                        <th scope="col">Full Name</th>
                        <th scope="col">Address</th>
                        <th scope="col">City</th>
                        <th scope="col">Zip</th>
                        <th scope="col">State</th>
                        <th scope="col">Country</th>
                        <th scope="col">Contact</th>
                        <th scope="col">Fax</th>
                    </tr>
                    </thead>
                    <tbody>
                            ..php coding here later
</tbody>
</table>
</div>
            </div>
        </div>
    </div>

*change the bold with your table heading content
*replace "..php coding here later" with these code below:

    1. Select data from database:
    <?php
     $sql = "SELECT id, user_email, user_fullname, user_address,         user_city, user_zip, user_state, user_country, user_tel,             user_fax from test_user";

*change test_user with your database name (and also don't forget to change the data name that you want to query)

    2. Execute the query above with these code:
    $result = $dbx->query($sql);
                    
                        if($result-> rowCount() > 0){
                            while($row = $result->                               fetch(PDO::FETCH_ASSOC)){
           echo "<tr><td>".$row["id"]."</td>        <td>"
                                .$row["user_email"] . "</td><td>"
                                .$row["user_fullname"]."</td><td>"
                                .$row["user_address"]."</td><td>"
                                .$row["user_city"]."</td><td>"
                                .$row["user_zip"]."</td><td>"
                                .$row["user_state"]."</td><td>"
                                .$row["user_country"]."</td><td>"
                                .$row["user_tel"]."</td><td>"
                                .$row["user_fax"]."</td></tr>";
                            }
                            echo "</table>";
                        }
                        else{
                            echo "0 result";
                        }
                    ?>

Done. You should be getting the expected result if you use them correctly with PDO and Bootstrap 5 (striped table). If you're using other MySQL method, please don't forget to browse on stackoverflow. Thank you.


0 Comment(s)


POSTED ON Monday 18 January 2021

 Android Studio problem [SOLVED]:


[1] Error Inflate XML in activity


Solution 1:

1. Remove <fragment tag from activity xml

2. Rather, replace it with a <FrameLayout

3. In activity class, simply setContentView(R.layout.fragment_register); //here, set the layout as the fragment id


Solution 2 (turns out my error is actually this)

1. Check the fragment class

2. My error was I did not inflate the fragment class 

------------

*note: any button or function should be made inside onViewCreated


[2] Error public void onComplete(@NonNull Task<AuthResult> task) { not succesful


Solution:

1. Add "uses INTERNET" in androidmanifest.xml

2. Make sure all variables in class User are accesible (make them public)


[3] Attempt to invoke virtual method 'void androidx.navigation.NavController.navigate(int)' on a null object reference


Solution:

1. Change navigate method 

from:

navController.navigate(R.id.action_registerFragment2_to_logIn);


to:

Navigation.findNavController(v).navigate(R.id.action_registerFragment2_to_logIn);



0 Comment(s)