Conversation
app.ts
Outdated
| } | ||
| } | ||
|
|
||
| let resizeTimeout: number; |
app.ts
Outdated
| $('#page').empty(); | ||
| $('#page').append(`Showing record: ${firstNumber} - ${count}`); | ||
| $('#loader').hide() | ||
|
|
app.ts
Outdated
| } | ||
| if (records[r].includes(inputValue)) { | ||
|
|
||
| lastRow.css('background-color', '#DDC0B4'); // hightlights the searched row |
app.ts
Outdated
| } | ||
| fetchColumns() | ||
|
|
||
| async function adjustRowsByScreenHeight(): Promise<number> { // calculates the number of rows that can fit the screen |
There was a problem hiding this comment.
I made a mistake because of my understanding, I will work on it.
app.ts
Outdated
| if (firstNumber < 0) { | ||
| firstNumber = 0; | ||
| lastNumber = firstNumber + (calculatedRows - 1); | ||
| } |
There was a problem hiding this comment.
move the else on the same line as the } please
app.ts
Outdated
| lastNumber = firstNumber | ||
|
|
||
| } | ||
| if (!lastNumber) { |
There was a problem hiding this comment.
this and the else does exactly the same
app.ts
Outdated
| @@ -0,0 +1,199 @@ | |||
| import { ajax, css } from "jquery"; | |||
| var firstNumber: number = 0; | |||
| var lastNumber: number; | |||
There was a problem hiding this comment.
would be nice to have a default
index.html
Outdated
| </table> | ||
|
|
||
|
|
||
| <script src="app.js"></script> |
There was a problem hiding this comment.
can move script tag into the head tag
DevinFledermaus
left a comment
There was a problem hiding this comment.
Some comments as initial changes
app.ts
Outdated
| @@ -0,0 +1,183 @@ | |||
| import { ajax, css } from "jquery"; | |||
| let firstNumber: number = 0; | |||
| let lastNumber: number = 0; | |||
There was a problem hiding this comment.
No need to set the variable and the type, either give a type, or set it
app.ts
Outdated
| if (!recordCount.ok) { | ||
| throw new Error('Failed to fetch record count'); | ||
| } | ||
| const data = await recordCount.json() |
There was a problem hiding this comment.
| const data = await recordCount.json() | |
| const data = JSON.parse(recordCount) |
app.ts
Outdated
| .then((columns: string[]) => { | ||
| const colArray = columns; | ||
|
|
||
| for (let c = 0; c < colArray.length; c++) { |
app.ts
Outdated
| if (calculatedRows === 0) { | ||
| lastNumber = firstNumber | ||
| } | ||
| if (firstNumber < 0) { |
There was a problem hiding this comment.
else if and move in the same line as }
app.ts
Outdated
| if (firstRow) { // checks if the first row exists | ||
| const cells = firstRow.querySelectorAll("td"); | ||
| const firstRecord: string[] = []; | ||
| cells.forEach((cell) => { |
There was a problem hiding this comment.
Rather make use of a for..of loop, even a for loop is fine, but for of is preferred
app.ts
Outdated
| import { ajax, css } from "jquery"; | ||
| let firstNumber = 0; | ||
| let lastNumber = 0; | ||
| let backend: string = "http://localhost:2050"; |
app.ts
Outdated
| } catch (error) { | ||
| throw new Error('Error fetching the record count') | ||
| }; | ||
| }; |
There was a problem hiding this comment.
No need for ; after declaring a function
app.ts
Outdated
| const jsonText = await response.text(); | ||
| const columns: string[] = await JSON.parse(jsonText); |
There was a problem hiding this comment.
| const jsonText = await response.text(); | |
| const columns: string[] = await JSON.parse(jsonText); | |
| const columns: string[] = JSON.parse(response.text()); |
app.ts
Outdated
| }; | ||
| }; | ||
|
|
||
| function adjustRowsByScreenHeight() { |
There was a problem hiding this comment.
no need to use the function keyword and provide a return type
app.ts
Outdated
| async function displayRecords(): Promise<void> { | ||
| try { | ||
| $('#loader').show(); | ||
| let count = await fetchRecordCount() - 1; |
app.ts
Outdated
| try { | ||
| const response = await fetch(`${backend}/records?from=${from}&to=${to}`); | ||
| if (!response.ok) { | ||
| throw new Error("Sorry, there's a problem with the network"); | ||
| } | ||
| return response.json(); | ||
| } catch (error) { | ||
| throw new Error('Error fetching records from server'); | ||
| }; |
There was a problem hiding this comment.
No need for the async anymore, and can remove the try and catch
| try { | |
| const response = await fetch(`${backend}/records?from=${from}&to=${to}`); | |
| if (!response.ok) { | |
| throw new Error("Sorry, there's a problem with the network"); | |
| } | |
| return response.json(); | |
| } catch (error) { | |
| throw new Error('Error fetching records from server'); | |
| }; | |
| return fetch(`${backend}/records?from=${from}&to=${to}`) | |
| .then(res => { | |
| if (!res.ok) { | |
| throw "Sorry, there's a problem with the network"; | |
| } | |
| return res.json(); | |
| }).catch(err => { | |
| throw 'Error fetching records from server ' + err; | |
| }); |
app.ts
Outdated
| import { ajax, css } from "jquery"; | ||
| class GlobalVariables { |
There was a problem hiding this comment.
Please leave an empty line between your imports and class definitions.
app.ts
Outdated
| resizeTimeout = 0; | ||
| //fetches the number of records from localhost | ||
| fetchRecordCount(): Promise<number> { |
There was a problem hiding this comment.
Please leave and empty line between your class attributes and your functions.
app.ts
Outdated
| firstNumber = 0; | ||
| lastNumber = 0; | ||
| backend = "http://localhost:2050"; | ||
| resizeTimeout = 0; |
There was a problem hiding this comment.
Please add a type to each of these variables.
app.ts
Outdated
| lastNumber = 0; | ||
| backend = "http://localhost:2050"; | ||
| resizeTimeout = 0; | ||
| //fetches the number of records from localhost |
There was a problem hiding this comment.
Please change this to a javadoc style comment. and instead of saying localhost, rather say "the backend attribute on this class"
app.ts
Outdated
| //fetches the number of records from localhost | ||
| fetchRecordCount(): Promise<number> { | ||
| return fetch(`${this.backend}/recordCount`) | ||
| .then((res) => { |
There was a problem hiding this comment.
Either remove the () around the res, or specify the correct type for res
app.ts
Outdated
| let inputValue = $('#searchInput').val() as number; | ||
| $('#page').empty(); | ||
| //calls to calculate the range once button is clicked | ||
| await updateRecordsAndResize(inputValue); |
There was a problem hiding this comment.
This function can throw an error, please catch it and handle it.
app.ts
Outdated
| rightArrow(); | ||
| }) | ||
| $('.arrow-left').on('click', () => { | ||
| leftArrow(); |
There was a problem hiding this comment.
This function can throw and error, please catch it and handle it.
style.css
Outdated
| } | ||
|
|
||
| .loader-spinner { | ||
| border: calc(200px / 10) solid #97694F; |
There was a problem hiding this comment.
calc is really really really bad, please don't use it.
style.css
Outdated
| justify-content: center; | ||
| align-items: center; | ||
| z-index: 9999; | ||
| } |
There was a problem hiding this comment.
Something happend with your formatting here.
style.css
Outdated
| height: 100px; | ||
| animation: spin 2s linear infinite; | ||
| background-color: #f7e7ce; | ||
| } |
CelesteNaude
left a comment
There was a problem hiding this comment.
Please make sure that all events that the user can fire off is debounced, i.e. search, resize, and buttons.
app.ts
Outdated
| @@ -0,0 +1,265 @@ | |||
| import { ajax, css } from "jquery"; | |||
|
|
|||
| class Myclass { | |||
There was a problem hiding this comment.
Please move the class into a separate file.
app.ts
Outdated
| const halfRange = Math.floor(calculatedRows / 2); | ||
| myClass.firstNumber = Math.max(0, inputValue - halfRange); | ||
| myClass.lastNumber = Math.min(recordCount, myClass.firstNumber + (calculatedRows - 1)); |
There was a problem hiding this comment.
If I understand correctly, you show the searched record in the middle of the grid and highlight it. In IMQS we show the most relevant record we're searching for at the top of the grid without formatting. But you can still keep the formatting because it's cool.
There was a problem hiding this comment.
Soooooo... I can't find an example that @CelesteNaude is talking about... I can only find two examples where we do it the way that you are doing it. But that has a lot to do with the fact that most of the time we filter instead of search.
(BTW @CelesteNaude, the two places is user-management, where we highlight and scroll to the user you just edited and the grids on the map, when you click on something on the map, and highlight and scroll to the feature you clicked on)
There was a problem hiding this comment.
This I remember from the advice that was given to me for my own onboarding project, weird.
app.ts
Outdated
| /** determines te value in the last row */ | ||
| const lastID = parseFloat(lastRecord[0]); | ||
| /** checks if the last value is within range */ | ||
| if (0 <= lastID && lastID <= (recordCount)) { |
There was a problem hiding this comment.
Don't need the () around recordCount
app.ts
Outdated
| } | ||
| /** determines te value in the first row */ | ||
| const firstID = parseFloat(firstRecord[0]); | ||
| if (0 <= firstID && firstID <= (recordCount)) { |
app.ts
Outdated
| @@ -0,0 +1,230 @@ | |||
| import { ajax, css } from "jquery"; | |||
|
|
|||
| const myClass = new Myclass(); | |||
There was a problem hiding this comment.
Global variables are bad, please remove them.
app.ts
Outdated
| @@ -0,0 +1,230 @@ | |||
| import { ajax, css } from "jquery"; | |||
|
|
|||
| const myClass = new Myclass(); | |||
There was a problem hiding this comment.
Also... please... please give it a better name... This name creates the idea that the Dev that made it isn't even aware of what it is used for.
app.ts
Outdated
| const myClass = new Myclass(); | ||
|
|
||
| /** Initializes the table head */ | ||
| function createTable(): Promise<string[]> { |
There was a problem hiding this comment.
I don't think this is the right name for your function. It seems to be adding headings to a dom element with the class head. Which does not sound like it is "creating a table".
I also don't know how I feel about returning an array of strings? Or anything for that matter. In my head a create* function is either creating something and returning it, or creating something somewhere and returning a reference to it. With the "returning a reference" being completely optional, and I your case I don't think you should be returning anything.
app.ts
Outdated
| } | ||
|
|
||
| /** calculates the number of rows that can fit the screen */ | ||
| const calculatingRows = (): number => { |
There was a problem hiding this comment.
... why make a constant variable that points to a function? You can just make a function. Please change this to just be a normal function.
app.ts
Outdated
| } | ||
| }) | ||
| .catch(err => { | ||
| throw new Error('Error occured while resizing' + err); |
There was a problem hiding this comment.
This is the last line of defense, you have to handle the error.
myClass.ts
Outdated
| @@ -0,0 +1,48 @@ | |||
| class Myclass { | |||
There was a problem hiding this comment.
As mentioned, please rename the class
myClass.ts
Outdated
| firstNumber: number = 0; | ||
| lastNumber: number = 0; |
There was a problem hiding this comment.
These two values are not being used in this class... Maybe you forgot to add methods using them? Or maybe they should not be in this class?
myClass.ts
Outdated
| firstNumber: number = 0; | ||
| lastNumber: number = 0; | ||
| backend: string = "http://localhost:2050"; | ||
| resizeTimeout: number = 0; |
There was a problem hiding this comment.
This value is not being used in this class... Maybe you forgot to add methods that uses it? or maybe it should not be in this class?
myClass.ts
Outdated
| } | ||
|
|
||
| /** fetches records from backend */ | ||
| fetchRecords(from: number, to: number): Promise<any[]> { |
| resizeTimeout: number = 0; | ||
|
|
||
| /** fetches the number of records from backend */ | ||
| fetchRecordCount(): Promise<number> { |
There was a problem hiding this comment.
You saaaaay number... yet you return res.json()... something is not adding up.
app.ts
Outdated
| if (this.firstNumber < 0) { | ||
| this.firstNumber = 0; | ||
| } else { | ||
| this.firstNumber = this.firstNumber; |
There was a problem hiding this comment.
Setting this.firstNumber equal to this.firstNumber? Sjoe 😢 Is the else then even necessary?
app.ts
Outdated
| }); | ||
|
|
||
| $('#searchInput').on('keydown', (event) => { | ||
| if (event.key === 'e' || event.key === 'E') { |
There was a problem hiding this comment.
Please rather make use of regex to stop the user from entering anything besides a digit.
app.ts
Outdated
| if (inputValue.includes('.')) { | ||
| $('#searchInput').val(inputValue.replace('.', '')); | ||
| } |
There was a problem hiding this comment.
With regex then these checks won't be necessary since you know the user could only type in digits.
app.ts
Outdated
| } | ||
|
|
||
| /** calculates the number of rows that can fit the screen */ | ||
| calculatingRows(): number { |
There was a problem hiding this comment.
| calculatingRows(): number { | |
| getNumberOfRows(): number { |
With a function name like that it is more descriptive of what it does. calculatingRows sounds like a boolean check like isCalculatingRows? Rather give it the verb of what it is going to do. I mean, since this function returns something how about get? How it got it is not maybe important. It calculated it, someone else calculated it? We just want the number of rows.
app.ts
Outdated
| const lastID = parseFloat(cells[0].textContent || ""); | ||
| // checks if the last value is within range | ||
| if (0 <= lastID && lastID <= this.recordCount) { | ||
| // calculates the first number of the page | ||
| this.firstNumber = lastID + 1; | ||
| const calculatedRows = this.calculatingRows(); | ||
| // calculates the last number of the page | ||
| this.lastNumber = this.firstNumber + (calculatedRows - 1); | ||
| } |
There was a problem hiding this comment.
The way I understand this function, you only need this part of the logic. You don't have to go and find the last child. You know what it is because you set it in this.lastNumber, right? Replace lastID with this.lastNumber and then you can remove the rest and just call this.updateAndDisplayRecords afterward.
app.ts
Outdated
| const firstID = parseFloat(cells[0].textContent || ""); | ||
| if (0 <= firstID && firstID <= this.recordCount) { | ||
| const calculatedRows = this.calculatingRows(); | ||
| this.lastNumber = firstID - 1; | ||
| this.firstNumber = this.lastNumber - (calculatedRows - 1); | ||
| } |
There was a problem hiding this comment.
Similar comment to the rightArrow function's comment. You don't have to rely on the HTML. You are the point of truth. Also, maybe a more descriptive function name instead of rightArrow and leftArrow? I mean, what does the function do? Navigate back and forth. Verbs instead.
style.css
Outdated
| .showRecords { | ||
| top: 0.8%; | ||
| right: 0; | ||
| padding: 1rem; |
There was a problem hiding this comment.
Rather make use of px instead of rem
app.ts
Outdated
| if (inputValue !== '') { | ||
| errorMessage = 'Failed to search, reload the page and search again'; | ||
| $('#loader').show(); | ||
| this.searchRecordsAndResize(); |
There was a problem hiding this comment.
Why not call this outside of updateAndDisplayRecords.
Call both this.searchRecordsAndResize and then this.updateAndDisplayRecords in your search input event?
FritzOnFire
left a comment
There was a problem hiding this comment.
Always try and handle errors as late as possible, otherwise your code will not be very portable and reusable.
app.ts
Outdated
| this.firstNumber = 0; | ||
| this.lastNumber = 0; | ||
| this.recordCount = 0; | ||
| this.initialize(); |
There was a problem hiding this comment.
I do not recommend calling functions that can throw errors in a constructor... You could technically still handle the errors, but the rest of your code would think everything went fine, when it very much did not.
Please call this initialize after creating a new instance of RecordManager
app.ts
Outdated
| this.createTableHeader(); | ||
| dataManager.fetchRecordCount() | ||
| .then(count => { | ||
| this.recordCount = count - 1; | ||
| this.updateAndDisplayRecords(); | ||
| this.recordEventHandlers(); | ||
| this.handleResize(); | ||
| }) | ||
| .catch(err => { | ||
| alert('Error fetching and displaying the table records, reload the page'); | ||
| throw err; | ||
| }); |
There was a problem hiding this comment.
So... two things.
-
Returning a promise makes catching errors much much easier for the calling function, so i would recommend always doing it. BUT
-
Here you are kicking off two
asyncfunction calls that do not depend on each other, which is beautiful :) This is a great way to speed up an app, but the calling function still needs to be able to handle the error of the function that you are not waiting for. And so now I will be breaking my own rule about not commenting exact code on an onboarding project. This is how you can wait on multipleasyncfunctions at the same time:
| this.createTableHeader(); | |
| dataManager.fetchRecordCount() | |
| .then(count => { | |
| this.recordCount = count - 1; | |
| this.updateAndDisplayRecords(); | |
| this.recordEventHandlers(); | |
| this.handleResize(); | |
| }) | |
| .catch(err => { | |
| alert('Error fetching and displaying the table records, reload the page'); | |
| throw err; | |
| }); | |
| let p: Promise<void>[] = []; | |
| p.push(this.createTableHeader()); | |
| let frcp = dataManager.fetchRecordCount() | |
| .then(count => { | |
| this.recordCount = count - 1; | |
| this.updateAndDisplayRecords(); | |
| this.recordEventHandlers(); | |
| this.handleResize(); | |
| }) | |
| .catch(err => { | |
| alert('Error fetching and displaying the table records, reload the page'); | |
| throw err; | |
| }); | |
| p.push(frcp); | |
| return Promise.all(p); |
app.ts
Outdated
| alert('Error fetching and displaying the table records, reload the page'); | ||
| throw err; |
There was a problem hiding this comment.
???
So you handle the error... and then you throw it anyway meaning that you have to handle it again later?
Please do not handle the error here, as who ever is calling initialize needs to know that we failed to initialize and they need to react accordingly.
app.ts
Outdated
| alert('Error creating table heading'); | ||
| throw err; |
There was a problem hiding this comment.
Similar comment as before about handling and then throwing again.
app.ts
Outdated
| alert('Error to fetch and display records, reload the page'); | ||
| throw err; |
There was a problem hiding this comment.
Similar comment as before about handling and then throwing again.
app.ts
Outdated
| $('#btnSearch').on('click', (event) => { | ||
| event.preventDefault(); | ||
| this.searchRecordsAndResize(); | ||
| this.updateAndDisplayRecords(); |
There was a problem hiding this comment.
You need to handle the error being thrown by updateAndDisplayRecords
dataManager.ts
Outdated
| if (!res.ok) { | ||
| throw 'Failed to fetch record count'; | ||
| } | ||
| return res.json(); |
There was a problem hiding this comment.
| return res.json(); | |
| return res.text(); |
dataManager.ts
Outdated
| return res.json(); | ||
| }) | ||
| .then(totalRecords => { | ||
| if(typeof totalRecords !== 'number'){ |
There was a problem hiding this comment.
Nice touch :) Now I kinda feel bad for asking you to not use json.
There was a problem hiding this comment.
This is a very creative way to hide the fact that you are using a global variable called backend. While there is nothing wrong with using static, and even making a class like this, as there truly is a time and a place for everything, its just unfortunately not in this on boarding project. Please remove all the static labels in this class.
This is basically as bad as turning off asynchronous requests in javascript for this project (I have only seen it once, and I am unable to find out how to do it, but I know it exists).
index.html
Outdated
| <p>Hello</p> | ||
| <div id="loader"> | ||
| <div class="loader-spinner"></div> | ||
| </div> |
There was a problem hiding this comment.
Your formatting is a bit off here.
No description provided.