Let’s Create a Daily Report App [Part 2: Registration and Viewing of Daily Reports]

Athina Hadjichristodoulou
The Web Tub
Published in
6 min readJul 5, 2023

If you’re considering using Monaca to develop an application, you might find it challenging to come up with ideas when the time comes. Additionally, if you’re planning to build a complex app from scratch, it can be overwhelming to know where to begin.

That’s why in this article, we will guide you through the process of developing a simple app. As a first step, we encourage you to take on the challenge.

In this tutorial, we will be developing a daily report app using NCMB (NIFCLOUD mobile backend). The tutorial is divided into two parts, and in the second part we will explain the process of report submission and viewing.

You can find the first part of this tutorial here.

Coding Time

Daily Report Input Screen Implementation

After logging in and returning to the report input screen, the user can start entering the report data. For this reason, we will create a category class for the ‘Category’ field in the NIFCLOUD mobile backend.

Please add a “name” field to the items and add a row for it.

This is then retrieved and set. This process only needs to be done once at screen initialization so we include it in the document.addEventListener(‘DOMContentLoaded’, e => {} function.

document.addEventListener('DOMContentLoaded', e => {
//Create new options for the category field
makeCategory();
}
/*
Categoty creation process
Add the data from the Category class in NCMB to the <select> tag
*/
async function makeCategory() {
const categories = await ncmb.DataStore('Category').fetchAll();
console.log("categories", categories)
const category = document.querySelector('#category');
categories.forEach(c => {
let option = document.createElement('option');
option.setAttribute('value', c.get('name'));
option.innerHTML = c.get('name');
category.appendChild(option);
});
}

Here we are searching the Category class and adding its items as option tags in the select tag.

Daily Data Registration Process

Next is the data registration process for the reports. This will be implemented as the event handling when the “#addItem” button is clicked in the report input screen. The function addItem handles this.

document.addEventListener('DOMContentLoaded', e => {
//Click event when the "Send Report" button is clicked
document.querySelector("#addItem").onclick = () => addItem.bind(this)();
}

Here’s an overview of the process. First, we gather the necessary information for the report.

//Process to add a daily report item
async function addItem() {
const date = new Date(document.querySelector("#date").value);
const user = ncmb.User.getCurrentUser();

//Create a datastore class
const Report = ncmb.DataStore('Report');
// Create an instance
const report = new Report();
// Set each item in the daily report as part of the instance
['description', 'time', 'category'].forEach(s => {
const selector = "#" + s
report.set(s, document.querySelector(selector).value)
});
//Set the rest of the items
report
.set('date', date)
.set('user', user);
// ACL Create access rights
const acl = new ncmb.Acl();
acl
.setUserReadAccess(user, true) // the person in question can read
.setUserWriteAccess(user, true) // the person in question can write
.setRoleReadAccess('admin', true); // users in the admin group can also read
report.set('acl', acl)
//Set and save ACL
await report.save();
//Screen redraw
refresh.bind(this)(date);
}

Next, we prepare to save the data in the NIFCLOUD mobile backend data store. Please refer to the comments for more details. As a note, for the Access Control List (ACL), the person who entered the data will have read and write permissions, and we grant read permission to the admin group. This allows users belonging to the admin group to view the data.

Finally, we execute the save process and perform the refresh process for the report.

Display Daily Report Data

After a successful saving process, we display the items of the reports that have been registered on the same date (using the refresh function mentioned above). In this case, we first retrieve the report information from the NIFCLOUD mobile backend (using the getItem function, which will be defined in app.js). Please refer to the comments for implementation details. One important note here is that if you are logged in as an administrator, you may retrieve reports from other users as well. To filter and display only the appropriate data, we use the information of the logged-in user.

//Process to refresh the screen
async function refresh(date) {
console.log("refresh")
//Retrieve data from daily reports
const reports = await getItem(date);
//Reflect the new data on the screen
viewReport.bind(this)(reports);
}
/*
Function to get daily report data from NCMB
Arguments:
date: Date to retrieve (date type)
all: Wether all data is targeted or not. All the data is targeted only for the admin accounts
Returned value:
array of daily report data
*/
async function getItem(date, all = false) {
const Report = ncmb.DataStore('Report');
const query = Report
.equalTo('date', date)
.include('user');
if (!all) {
const user = ncmb.User.getCurrentUser();
query.equalTo('user', {
__type: 'Pointer', className: 'user', objectId: user.objectId
});
}
return await query.fetchAll();
}

Once the data is retrieved, we display it as a list using <ul> tag. One important implementation note here is that we display a delete icon and set a click event on it for deletion purposes. Since this is a dynamically added DOM element, we set the event after the element is added.

//Process to display daily report data
function viewReport(reports) {
const html = [];
console.log("reports: ", reports)
reports.forEach(r => {
//Make a list item for each report
html.push(`
<li>
<block>
<div class="item-content grid grid-cols-3 grid-gap">
<div class="item-inner">
<div class="item-title">${r.get('time')} / ${r.get('category')}&nbsp;</div>
<div>&nbsp;${r.get('description')}</div>
<div class="item-after deleteItem">
<a><i class="icon material-icons if-md" data-id="${r.get('objectId')}">delete</i></a></div>
</div>
</div>
</block>
</li>
`);
});
//Reflect it in the DOM
document.querySelector('#reports').innerHTML = html.join('');
//Add a deletion event to the trash icon for every listing
document.querySelectorAll('.deleteItem').forEach(d => {
// When the icon is clicked
d.onclick = (e) => {
console.log(e)
//Obtain object id
const objectId = e.target.dataset.id;
//Data deletion
deleteItem.bind(this)(objectId);
}
});
}

Deletion of Daily Report Data

The implementation of the delete event we added earlier is as follows; It involves deleting the data from the data store in the NIFCLOUD mobile backend and updating the list. The `objectId` represents the unique ID of the data in the NIFCLOUD mobile backend. When performing data updates or deletions, this unique ID is used to specify the data. Once the deletion process is completed, the list is once again updated.

/*
Deletes a daily report item
Arguments:
objectId: String. Unique ID of the class.
*/
async function deleteItem(objectId) {
//Greate a DataStore class
const Report = ncmb.DataStore('Report');
//Create an instance of the class
const report = new Report();
//Set the objectId and delete
await report
.set('objectId', objectId)
.delete();
//Get the date for screen refresh
const date = new Date(document.querySelector("#date").value);
//Refresh the screen
refresh.bind(this)(date);
}

Daily Report Display Screen Creation

Finally, let’s create the daily report display screen. This is similar to the previous display of report data, but we won’t include the delete icon. First, we’ll implement the retrieval of report data when the ‘Browse’ tab is clicked inside the document.addEventListener(‘DOMContentLoaded’, e => {} function.

document.addEventListener('DOMContentLoaded', e => {
//Set today's date in Browse screen
const day = dayjs().format('YYYY-MM-DD');
document.querySelector("#todaysDate").innerHTML = day
document.querySelector("#browseTab").onclick = () => refreshBrowse.bind(this)(new Date(day))
}
async function refreshBrowse(date) {
console.log("refresh browse")
//Retrieve all the data from daily reports
const reports = await getItem(date, true);
//Reflect it on screen
viewBrowseReport.bind(this)(reports);
}

The actual process will be as follows. First, we retrieve the data from the NIFCLOUD mobile backend. We will utilize the `getItem` function that we defined earlier in `app.js`. This time, we are retrieving all the data without any user restrictions (the second argument `true` is a flag indicating all data). We display the data inside the `#admin-reports` element in the file browse.html.

/*
Process to display daily report data in the Browse screen
Arguments:
reports: Array type. Daily report data to be displayed
*/
function viewBrowseReport(reports) {
const user = ncmb.User.getCurrentUser();
const admin = user.get('admin');
const html = [];
console.log(reports)
reports.forEach(r => {
//Retrieve username
const name = `<div class="item-after">${r.get('user').displayName}</div>`;
html.push(`
<li>
<block>
<div class="item-content grid grid-cols-2 grid-gap">
<div class="item-inner>
<div class="item-title">${r.get('time')} / ${r.get('category')}&nbsp;</div>
<div class="item-title">&nbsp;${r.get('description')}</div>
${admin ? name : ''}
</div>
</div>
</block>
</li>
`);
});
//Reflect it in the DOM
document.querySelector('#admin-reports').innerHTML = html.join('');
}

Summary

With this, the daily reposting system is complete. In this development, we created an app with the following screens:

- Authentication screen

- Daily input screen

- Daily display screen

Additionally, we utilized the following features of NIFCLOUD mobile backend:

- User management:

  • User registration with ID/password
  • ID/password authentication

- Datastore

  • Category class
  • Data retrieval

- Report class

  • Data registration
  • Data deletion
  • Data search

The functionalities we implemented for data storage, retrieval, and authentication are essential features applicable to various types of apps. Feel free to apply them in your future app development projects now that you are more comfortable using them.

You can find the code for this project in this GitHub repository.

--

--