Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Friday, October 11, 2019

Download data in CSV format using JavaScript

Today we would be discussing Export to CSV functionality using JavaScript. You might be wondering that there are many 3rd party libraries to generate the CSV file using JavaScript/jQuery then why am I reinventing the wheel? Why don't use the already existing solution? Bear with me, I would not only explain why but also describe how to download data in CSV format using JavaScript?

1. Introduction 


It's the very common use-case that we already have some data on the browser (HTML pages) and we would like to provide the option to users to download these data in CSV format using jQuery / JavaScript. That's why there are many 3rd party libraries in the market to generate the CSV file using jQuery but from the HTML table as the source. Just lookout for a solution that facilitates us to generate the CSV file using jQuery / JavaScript if the current HTML structure representing the data on the page is not in the tabular format. This is where our solution comes in the picture which is very simple and handy. One might argue that it is possible to create a temporary table from the complicated HTML structure on the fly in order to use the 3rd party libraries. But again it depends upon the complexity and we won't be discussing that here. 

2. Browser Compatability 


Tested this utility in below version of the browser and it's working as expected:
  • Google Chrome Version 77.0.3865.90 (64-bit)
  • Firefox Quantum Version 69.0(64-bit)
  • IE 11 Version 11.0.9600.19467

3. Why & Implementation


Now again we would reiterate one which situation and why one should use this Export to CSV utility developed using JavaScript and then directly jump on the implementation.

3.1 Why? 

  • Preferred to use if the current HTML structure is not in tabular format and very complicated  but one could use it even if HTML structure is in tabular format 
  • Handling boundary usecases: Currently if data values have comma then also it properly handles it. 
  • Simple to use
  • Don't have to load any 3rd part library 

3.2 Implementation 


One needs to just create the multi-dimensional data array from the HTML page containing the data using jQuery / JavaScript and then we are good to go. Here for the demo purpose, we have created the multi-dimensional data array manually inside JavaScript. 
<html>
<head>
<title>Download CSV</title>
<script>
// prepare the data from the HTML page using jQuery/JavaScript.
// Demo purpose, we are manually preparing the data
var data = [
   ['Anshul', 'programmer','Gamer'],
   ['Rahul', 'Computer Science Engineer','Traveller'],
   ['Rajnikant', 'Hero','Sky Ga,zing']
];


function downloadCSV() {
    var csv = 'Name,Job,Passion\n';
 
 data.forEach(function(row) {
        var row1 = []; 
        row.forEach(function(item) { // handling commna in data values
        if(item.indexOf(',') == -1) { // not having comma 
    row1.push(item);
  } else {
    item = "\"" + item + "\"";
    row1.push(item);
  }
     });
 console.log("row1:" + row1)
 csv += row1.join(',');
 csv += "\n";
     });
 
 if (navigator.msSaveBlob) { //IE
  var csvURL =  null;
  var csvData = new Blob([csv], {type: 'text/csv;charset=utf-8;'});
                csvURL = navigator.msSaveBlob(csvData, 'download-reports.csv');
 } else { // Firefox,Chrome
         console.log(csv);
  //var hiddenElement = document.createElement('a');
                var hiddenElement = document.getElementById('dummyDownload'); //For Firefox 
  hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
  hiddenElement.target = '_blank';
  hiddenElement.download = 'download-reports.csv';
  hiddenElement.click();
    }  
}
</script>
</head>
<body>
<a id=dummyDownload hidden></a> 
<button onclick="downloadCSV()">Download CSV</button> 
</body>
</html>

4. Downloaded CSV File


For reference, showing the downloaded CSV file in both the notepad++ & by Open Office(Separated by option: Comma). See the last row in which, intentionally I have put a comma in one of the data values but our utility properly handles it. 


5. Conclusion


Now you know how to integrate Download CSV functionality in your application which is pretty simple.  Let me know in the comments if it's working for you or not. Happy Learning!! ☺

How to add jQuery datetimepicker in the page?

Today we would be looking at the jQuery datetimepicker implementation. It improves the User Experience. One needs to make a few things in mind for datetimepicker integration like
  • Adding the required HTML code snippet in the page for selecting the date & time i.e. adding input element of type text  
  • Respective JS & CSS libraries(datetimepicker and jQuery related) should be included in the page
  • Activating the datetimepicker using jQuery or JavaScript 
After configuring the datetimepicker, it would look like below:


Implementation:


<html>
<head>
<title>Datetimepicker Demo</title>
<!–– Respective JS & CSS libraries(datetimepicker and jQuery related) should be included in the page ––>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.min.css" rel="stylesheet"/> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.full.min.js"></script>
<script>
$(document).ready(function () {
   // Activating the datetimepicker using jQuery or JavaScript 
   $('#datetimepicker1').datetimepicker(); //default    
   $('#datetimepicker2').datetimepicker({ //customized
      format:'d/m/Y H:i',
      minDate:0,
      formatTime:"h:i a",
      step:10,
      // if one would like to take user selected input from datetimepicker and atomatically round off to nearest integral of 10 minutes
      onChangeDateTime:function(dp,$input){
      //27/10/2019 12:01 -> dateTime[0] = date, dateTime[1] = time
 var dateTime = $input.val().split(" "); 
 var time = dateTime[1].split(":");
 var hour = time[0];
 var minutes = time[1];
 var datetimestring;
    
 if(minutes > 0 && minutes < 10) {
         datetimestring = dateTime[0] + ' ' + hour + ':' + 10;
         $input.val(datetimestring);
  }
    ...
  } // end of onChangeDateTime function
   });
   
});
</script>
</head>
<body>
<!–– Adding the required HTML code snippet in the page for selecting the date & time i.e. adding input element of type text  ––>
Default Datetimepicker:
<input type="text" id="datetimepicker1" placeholder="select date time">
Customized Datetimepicker:
<input type="text" id="datetimepicker2" placeholder="select date time">
</body>
</html>

Hoping that it would help you. Happy Learning!! ☺

Friday, September 20, 2019

How to prevent click on the specified HTML element using CSS, JS or jQuery

Recently I have got a simple requirement of making specified HTML element non-clickable conditionally. I am free to choose how to implement this i.e. either by using CSS, JS, jQuery. Today I would be sharing how I have achieved this. It might be not the best or optimal solution but it worked for me. Let me know what could be another possible solution for this.

Since the requirement was to make some HTML element non-clickable conditionally, I have used both jQuery and CSS to achieve the complete requirement. But I have used CSS property pointer-events: none to prevent the click on the specified HTML element. The pointer-events property defines whether or not an element reacts to pointer events. Here, I used two of its values i.e.
auto : The element reacts to pointer events, like hover and click. This is default
none : The element does not react to pointer events
$('#topicMenu').children('li:not(.selectedTopic)').css("pointer-events","auto"); //making it again clickable
$('#topicMenu').children('li:not(.selectedTopic)').css("pointer-events","none"); //making it non-clickable

Later I came through one more method using jQuery in StackOverflow but haven't verified it if it really works:
$('selector').click(false); //If using jQuery versions 1.4.3+:
$('selector').click(function(){return false;}); //else 
Feel free to share any new way to make the specified HTML element non-clickable. Happy Learning!!

Thursday, May 10, 2018

Thymeleaf: jQuery/JavaScript function call with or without parameters (Examples)

While developing our web application, it's very common use case to execute JavaScript functions on an account of any event like onblur, onchange, onclick, onkeydown, onmouseover etc [1]. These calls may be with or without parameters depending upon the business requirement.
             Today, we would see some examples to understand how to properly call JavaScript functions from Thymeleaf. But before that, we would also see used tech stack, Thymeleaf dependencies in the POM file and how we have added page fragments containing our CSS &  JS files in the target HTML page where we would be making the JavaScript function calls.



1. Tech Stack:


- Spring Boot 1.5.10.RELEASE
- Maven 3.3.9
- Thymeleaf 3.0.3.RELEASE

2. Thymeleaf Dependencies in Maven POM file

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
 <groupId>org.thymeleaf</groupId>
 <artifactId>thymeleaf</artifactId>
 <version>3.0.3.RELEASE</version>
</dependency>
<dependency>
 <groupId>org.thymeleaf</groupId>
 <artifactId>thymeleaf-spring4</artifactId>
 <version>3.0.3.RELEASE</version>
</dependency>
<dependency>
 <groupId>nz.net.ultraq.thymeleaf</groupId>
 <artifactId>thymeleaf-layout-dialect</artifactId>
 <version>2.1.2</version>
</dependency>

3. Add external JavaScript file to the HTML page


For cleanliness and better maintainability, I have kept almost all of my JavaScript functions in a separate JS file which is located at <project_name>/src/main/resources/public/js/main.js and then added the fragment containing CSS & JS in HTML file using th:replace attribute.

3.1 The Fragment 

## <project_name>/src/main/resources/templates/fragments/header.html
<head th:fragment="cssandjs">
 <title>Anshul's Blog</title>
 <link rel="stylesheet" type="text/css" th:href="@{/css/screen.css}"/>
 
 <script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>
 <script type="text/javascript" th:src="@{/js/main.js}" src="/js/main.js"></script>
</head>

3.2 The Target HTML page 


This is the file where we have added the cssandjs fragment using th:replace attribute and will be making JavaScript calls using Thymeleaf. For more details on th:replace attribute, have a look at this write-up.
## <project_name>/src/main/resources/templates/target.html
<head th:replace="fragments/header :: cssandjs">

4. jQuery / JavaScript Function Calls


Apart from function calls, we would also see situations where we may avoid writing JavaScript functions. One might confuse while making function calls as when to directly use events like onclick, onchange etc or use Thymeleaf's attributes like  th:onclick or th:onchange etc. Therefore, just follow the golden rule i.e. use Thymeleaf's attributes only when, we need to pass some dynamic values in the functions otherwise stick with normal HTML event attributes. Now we ready to fly, everything is in place.

4.1 Function call without parameter

<button onclick="addItemToKart()">Add Item</button>
<div class="close"><span id="x" onclick="closeItemDetailsInModelWindow()">&#9747;</span></div>
<select th:name="${#strings.listSplit(stream.key,',')[1]}" 
  th:onchange="${#strings.listSplit(stream.key,',')[1] == 'Science'} ? 'populateScienceOrCommerceDropdown()' : ''">

4.2  Function call with parameters

## ${item.id} is of type Integer
<input type="button" value="Select" th:onclick="|showItemDetailsInModelWindow(${item.id})|"/>

## ${author.id} is of type Integer & ${author.name} is of type String
<input type="button" value="Show books by author" th:onclick="|showBooksByAuthor(${author.id}, '${author.name}')|"/>

## ${titleModel.isbn} is of type String & ${book.bookId} is of type Integer
<a th:onclick="|bookDetails('${titleModel.isbn}',${book.bookId})|" style="cursor: pointer;">Book Details</a> 

4.3 Avoid writing JavaScript functions


In some situations, one could avoid writing JavaScript functions like when one have to simply call a particular controller's method or when one have to show the popup box [Alert box, Confirm box, and Prompt box] etc.
<button th:onclick="'javascript: document.location=\'/chapterdetails?isbn=' + ${bookModel.isbn} + '&amp;page=1\''"></button>  
<input type="submit" value="Approve" onclick="return ( prompt('You must type APPROVED to continue') == 'APPROVED' )" /> 

5. Conclusion 


Now we know how to make JavaScript function calls in Thymeleaf. We have also seen how to keep function calls in a separate file for better maintainability and then use th:replace attribute to add the fragments containing these CSS & JS files. Happy Learning!!

Appendix:
[1] : Some examples of event attribute and their corresponding event actions:
  • onclick Event:
    - 
    onclick of a button, invoke a controller method with or without parameter
    - onclick of a button, open a model window to either show some information to user or to take user's input
  • onchange Event:
    - 
    dynamically showing different select box on selecting different values from a select box