Youtube channel !

Be sure to visit my youtube channel

Wednesday, December 25, 2019

Sorted to do list in JavaScript

JavaScript is a wonderful language as you may discover in the JavaScript for beginners - learn by doing course.

Here is a short working example on how we can easily sort todos saved inside an array:

The initial HTML markup:
<input id="myInput" type="text" /><button id="Add"> Add new LI </button>
<ul class="todoList"></ul>

<script>
// initial array to hold the todos
const todos = [];

// we have helper function for doing the actual sorting
const doSort = (todos) => {
return todos
// .map(todo => todo.toLowerCase()) // make all the items lowercase
.sort((a, b) => {
// compare 2 words letter by letter
if (a.value > b.value) { return 1; } // when the first letter is after the second
if (a.value < b.value) { return -1; } // when the second letter is before the second
return 0; // if both letters are the same
 }) 
} // attach event listener to the Add button document.querySelector('#Add').addEventListener('click', () => {

// get what's inside the input
const data = document.querySelector('#myInput');

// push the new todo into the todos array
todos.push(data.value);

// create additional helper array with object values and indexes
var mapped = todos.map(
(el, i) => ({ index: i, value: el.toLowerCase() })
);

// sort the todos
const sortedTodos = doSort(mapped)
// restore the originals from the todos array
.map(el => todos[el.index]);

// display the sorted totos
todoList.innerHTML = sortedTodos.map(todo => '<li>' + todo + '</li>').join('');

// clear the value of the input
data.value = '';
});

//get reference to the todoList
const todoList = document.querySelector('.todoList');

</script>

Congratulations!

Resources:

JavaScript for beginners - learn by doing

Thursday, December 19, 2019

To do list in Angular

Here is how to create a simple todo-list in Angular. We will be also using extensively RxJs BehaviorSubject as well as Observables. If you want more information on the techniques used, I advise you to practice with the full Angular for beginners course.




First install angular with: sudo npm i -g @angular/cli
Then create a new todo project: ng new todo
Inside the todo directory create 2 new components and service using the Angular CLI:
ng g c todos
ng g c form
ng g s services/todos

Next, modify the following files:
app.component.html
// to include the new component tags
<div class="container">
<h1>{{appTitle}}</h1>
<app-todos [limit]="3"></app-todos>
<app-form></app-form>
</div>
...
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { TodosComponent } from './todos/todos.component';

// import httpclientmodule to be able to perform http requests
import { HttpClientModule } from '@angular/common/http';

// import forms module to be able to use 2-way [(binding)]
import { FormsModule } from '@angular/forms';
import { FormComponent } from './form/form.component';

@NgModule({
declarations: [
AppComponent,
TodosComponent,
FormComponent
],
// and place it (FormsModule) inside modules to be visible by all derived services and componenets
imports: [
BrowserModule,
HttpClientModule,
FormsModule //  add into imports the formsmodule to be accessible from the components
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

...
form.component.html

<div>
<input type="text" placeholder="Add todo..."
<!-- bind the title input field of the form to the model this.title -->
[(ngModel)]="title"
<!-- allow with enter to be able to run addTodo() -->
(keydown.enter)="addTodo()" />
<button (click)="addTodo()">Add todo</button>
</div>

...
form.component.ts

import { Component } from '@angular/core';
// import both the interface Todo as well as the TodoService
import { Todo, TodosService } from '../services/todos.service';

@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.scss']
})

export class FormComponent implements OnInit {
// title will be bound to the title input of the form
title: string = '';

// use dependency injection to inject the TodosService
constructor(private todosService: TodosService) { }

addTodo() {
// construct todo object and add it using the service
const todo: Todo = {
id: Date.now(),
title: this.title,
complete: false,
}
this.todosService.addTodo(todo);
}
}
...


todos.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { TodosService, Todo } from '../services/todos.service';
import { Observable } from 'rxjs';

@Component({
selector: 'app-todos',
templateUrl: './todos.component.html',
styleUrls: ['./todos.component.scss']
})
export class TodosComponent implements OnInit {

constructor(private todosService: TodosService) { }
private fetchData$: Observable<boolean>;
private todos$: Observable<Todo[]>;

// receive the limit from the parent(appcomponent) via input
@Input() limit: number;

ngOnInit() {
// initialize the both observables
this.fetchData$ = this.todosService.getTodos(this.limit);
this.todos$ = this.todosService.todos$;
}

// call the service
onChange(id: number) {
this.todosService.onToggle(id);
}

// call the service
removeTodo(id: number) {
this.todosService.removeTodo(id);
}

}

...

todos.component.html

<!-- mainly to fetch the http json data & setup this.todos -->
<div *ngIf="(fetchData$ | async ); else errorFetch"></div>

<!-- get the observable data and spread it on the page -->
<ul *ngIf="(todos$ | async ) as todos; else loading">
<li *ngFor="let todo of todos; let i = index">
<span [class.done]="todo.complete">
<input type="checkbox" [checked]="todo.complete" (change)="onChange(todo.id)">
<!--  bind [checked] to the state complete of todo
 pass todo.id on(change) event,
and run onChange function from the .ts file
-->
{{i + 1}} {{todo.title}}
</span>
<small>{{todo.date | date}}</small>
<!-- use pipe date to format the data: you can see other pipes from API/datepipe on angular website -->
<button class="remove" (click)="removeTodo(todo.id)">×</button>
</li>
</ul>

<ng-template #loading> Loading, please wait ...</ng-template>
<ng-template #errorFetch> There is an error while loading the data, please try again ...</ng-template>

...

todos.service.ts

import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject, of } from 'rxjs';
import { tap, map, catchError } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

// create interface with the structure of a simple todo item
export interface Todo {
id: number
title: string
complete: boolean
}

@Injectable({
providedIn: 'root'
})
export class TodosService {

constructor(private http: HttpClient) { }
public todos: Todo[] = [];
private subject = new BehaviorSubject<Todo[]>([]); // to be able to retain the last emitted version !
public todos$ = this.subject.asObservable();

getTodos(limit: number): Observable<boolean> {

return this.http.get<Todo[]>(`https://jsonplaceholder.typicode.com/todos?_limit=${limit}`)
//  just return observable of true or false
.pipe(
map((fetchedTodos: Todo[]) => {
// setup the local this.todos member
this.todos = fetchedTodos;
// propagade the todos to subscribers via subject
this.subject.next(this.todos);
return true;
}),
catchError(err => {
alert(err.message);
return of(false);
})
);
}

onToggle(id: number) {
// get the todo index by the provided ID
const idx = this.todos.findIndex(todo => todo.id === id);
this.todos[idx].complete = !this.todos[idx].complete;
}

removeTodo(id: number) {
this.todos = this.todos.filter(todo => { return todo.id !== id }
);

// propagade the updated data back to all observables
this.subject.next(this.todos);
}

addTodo(todo: Todo) {
this.todos = [...this.todos, todo];
this.subject.next(this.todos);
}
}

Now you can run: ng serve
and browse: http://127.0.0.1:4200

Congratulations and enjoy learning Angular.

Sunday, December 15, 2019

Immutable JavaScript / ES6 to do list

Here is my interpretation of how to create a simple JavaScript ToDo list based on immutability and states. You may also enjoy the JavaScript for beginners - learn by doing course.

So far there are only add and delete actions created:
<input id="myInput" type="text" /><button id="Add">Add new Todo </button>
<div id="app"></div>

<script>
// state object
var state = {
name: 'todo list 1',
todos: [{ id: 1, data: 'first todo <button class="delete" data-id="1">X</button>' }]
};

//we pass the todo as object({with id, and the todo_info})
function applyAction(todo, action) {
switch (action) {
case 'add':
return [...state.todos, todo];
break
case 'remove':
//here remove it from index using todo.id
return state.todos
.filter(dbTodo => dbTodo.id !== todo.id);
break
case 'update':
// return [
// ...state.todos
// .filter(dbTodo => dbTodo.id !== todo.id), // first we remove the soon to be updated todo
// todo // then we add the updated version to the end of the array
// ];
return state.todos.map(
dbTodo =>
// whe check when we have match on id, we use todo, otherwise we leave the original dbTodo
dbTodo.id === todo.id ? todo : dbTodo
);
break
}
}


let renderTodos = todos => {
return `
<ul>${state.todos.map(todo => `
<li>${todo.data}</li>
`)} `;
}


// The state-based UI rendering
var render = state => {
var html = `
<h1>
${state.name}</h1>
${ state.todos.length < 1 ? 'Please add a todo' : ''} ${renderTodos(state.todos)} `; app.innerHTML = html; }; let setState = obj => {
// update the state with passed object
Object.keys(obj).forEach(key => {
state[key] = obj[key];
});
//update the render
render(state);
}

// Add todo event listener
document.querySelector('#Add').addEventListener('click', () => {
// get what's inside the input
const inputData = document.querySelector('#myInput');
if (inputData.value == '') return;
// just mapping into new array only the ids, then doing max on them
let lastId = (state.todos.length > 0) ? Math.max(...state.todos.map(todo => todo.id)) : 0;
current_todo = { id: ++lastId, data: `${inputData.value} <button class="delete" data-id="${lastId}">X</button>` }
setState({ //save the modified state and show the result
todos: applyAction(current_todo, 'add') // apply the add modification to the state
});
// clear the value inside the input
inputData.value = '';
});

// Remove todo event listener
document.querySelector('#app').addEventListener('click', (e) => {
if (e.target.classList.contains('delete')) {
const id = +e.target.getAttribute('data-id'); // convert the string data-id to number
const currentTodo = { id };
setState({ // save the modified state and show the result
todos: applyAction(currentTodo, 'remove') // apply the add modification to the state
});
}
});

// Render the initial UI
var app = document.querySelector('#app'); render(state);
</script>

Congratulations ! 

Resources:

JavaScript for beginners - learn by doing

Friday, December 06, 2019

How to prevent Burnout in the IT


Let's first think about what might cause it:
Burnout is a more and more frequent condition in the IT-sphere and is usually caused by working in a toxic work culture which includes:
- not enjoying the colleagues double-faced behavior, or what they do with their money :)
- colleagues who might be trying to get you out of their career path
- experiencing a non-supportive mixed joking / passive-aggressive behavior from supervisors, without being able to respond
- not enjoying the technologies working with such as outdated software, frameworks or languages
- trying to keep up with the pace by learning, and at the same time thinking if you don't know in details about the latest updates, you won't fit inside the team and will be fired
- trying to schedule your rest/work time, by being flooded at an unexpected time with task tickets (time-restricted)
- not having the opportunity to express your view on certain subjects, or when expressing them they are left without a response
- thinking that the whole IT sphere is getting more and more filled with people, who can as well as pick potatoes if the job is well payed
All those can quickly build up and you may start to have repetitive negative thoughts about doing the work and at the same time trying to be cheerful around the colleagues - a form of cognitive dissonance.

The following are my remedies:
You'll need to learn to quickly how to balance between your focused and default brain network:
Have at least 1 hour of walks in fresh air.
Here is some immediate basic exercise, you can do without postponing :)

Do sports, running combined with positively reinforced repetitions of I am ok, I am healthy... fill in some empowering words that work for you...
Work on a standing desk in order to reinforce your focused network, and having breaks as much as you would like. Remember your job and that of an HR is not of the same difficulty :) If, on a budget, you can do standing desk by yourself using some books or cardboard boxes.
Optional: extensively use high-quality headphones
About performing tasks: write the task, in the form of a mini and detailed plan on how to do the task and then just relax and have fun. When it is time to choose to do a particular task, just open the plan and do it, without having to think or improvise ways on what is the proper way to do the task or which task to choose.
Lastly - simply quit your job.

Event delegation in JavaScript

In JavaScript we use event delegation for two main reasons:
1) to be able to process events coming from dynamically added page elements.
2) to achieve better application performance by listening to only one main element instead of having to add and remove event listeners each time a new element is dynamically added to the DOM.
More intriguing JavaScript aspects you can discover inside the JavaScript for beginners - learn by doing course.

 


In case of event delegation, when event occurs, we can filter out on which of the event generated source elements we would like to respond to using the event's target property: event.target
Here are two examples on how to use the event target:
// to filter out the processing of events coming from elements having different classes:
if (!event.target.classList.contains('my_class')) return;
// or to do filtering based on particular tag:
if (event.target.tagName == 'INPUT') {
// do our processing only if the source event came from an input tag
}

Example: Here we create an html with a simple ul/li list and add new LI button:
<button id="add">Add new LI</button>
<ul class="characters">
    <li>
        <input type="checkbox" data-index="0" id="child0">
        <label for="child0">Child 0</label>
    </li>
    <li>
        <input type="checkbox" data-index="1" id="child1">
        <label for="child1">Child 1</label>
    </li>
    <li>
        <input type="checkbox" data-index="2" id="child2">
        <label for="child2">Child 2 </label>
    </li>
</ul>
<script src="event_delegate.js"></script>

And here is our JavaScript code which adds new LI elements dynamically:
document.querySelector('#add').addEventListener('click', () => {
 // we create a new li element
let li = document.createElement('li');
// we get the last data-index attribute withing ul>li
    let dataId = characterList
        .lastElementChild // we use ElementChild instead of Child, because it ignores text and comment nodes
        .firstElementChild
        .getAttribute('data-index');
// increase the last id with 1
    ++dataId;
// construct the ne LI element with increased dataId
    li.innerHTML = `
    <input
    type="checkbox"
    data-index="${dataId}"
    id="child${dataId}">
    <label for="child${dataId}">Child ${dataId}</label>
    `;
// append the new LI eleemnt to the UL
    characterList.append(li);
});

// this is our little debug function showing up the event and where it is coming from
function toggle(event) {
    console.log('event: ' + event); //the event
    console.log('target: ' + event.target); //where occured the event
    console.log('currentTarget: ' + event.currentTarget); //attached parent element
    console.log('toggled element with id: ' + event.target.id);
}

// the actual parent element, where the event delegation is happening
const characterList = document.querySelector('.characters');
// here, instead of having multiple LI attached event listeners, we just attach 1 event listener to the UL list
characterList.addEventListener('click', toggle);

// Bonus: here is how to query specific element using its data-index attribute:
console.log(document.querySelector('input[data-index="1"]'));

Congratulations!

Resources:

JavaScript for beginners - learn by doing

Tuesday, November 26, 2019

One way data binding in JavaScript

Alright, since two-way data binding is often used in Angular, React and Vue and at the same time, not everyone likes it. I think that simple one-way data binding when writing JavaScript code is actually beneficial. More intriguing JavaScript aspects you can discover inside the JavaScript for beginners - learn by doing course.


What is one-way data binding: simply-said we would like the moment we change our data variable (model) this change to reflect immediately inside our generated HTML. Let's take a look at this example:
We have two span elements with two data bindings quote1 and quote2. You may consider them as just ids:
<span data-binding="quote1"></span>
<br>
<span data-binding="quote2"> </span>

Then we create the HTML change function (render) that will grab the element that is passed as a "property" parameter and will change its innerHTML based on what is inside the same property, taken from a special state object. This way effectively changing the HTML based on a passed parameter.

const render = property => {
document.querySelector(`[data-binding="${property}"]`).innerHTML = state.property;
};

Now to the main function setState. Its goal is to create a Proxy around a passed state obect, and whenever property of an object inside this state changes (i.e. user puts information inside (set)), the proxy will perform certain things, such as: setting the updated value inside the property, as well as using the previously defined render function to update the HTML view):

const setState = state => {
return new Proxy(state, {
set(target, property, value) { // detect if there are changes inside the property of a certain object
target.property = value; // updates the value of the property
render(property); // renders the HTML with the updated property to the screen
}
});
};

Now lets set an initial state:
const state = setState({
quote1: 'Initial quote state.'
});

Once it is set we can display the initial state on the console: console.log(state.quote1);

We can now try to modify some properties inside the Proxy state:
state.quote1 = 'quote1 new state';
state.quote2 = 'quote2 new state';
and see how their updated changes are reflected on the browser HTML.

You now may use the Proxy design pattern for your projects. 

Congratulations!

Resources:

JavaScript for beginners - learn by doing

Monday, November 25, 2019

Create REST API with NodeJS

An introductory part of the Learn Node.js, Express and MongoDB + JWT course.


First, we will install the latest npm and nodejs version from nodesource: https://github.com/nodesource/distributions

curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash -
sudo apt-get install -y nodejs

Then we will create a directory API, where we will set up our project:
mkdir api
npm init
(please provide project name, description, and author name as information)
Then is time to install some required packages:
We will install express in order to act as a web server together with nodejs: npm i express
Open the package.json file and notice how now express appears under the dependencies section.

We will also install MongoDB as well as MongoDB as our database and a mongoose DB connection helper with npm i mongodb mongoose
Then we will do a babel installation. Babel (/preset-env) will transpile (convert) our code so it can become cross-browser compatible, this is especially useful when you want to achieve better JavaScript support. Babel (/node) will provide understanding to nodejs of the modern ES features we will be using inside the index.js file.
npm i --save-dev @babel/preset-env @babel/core @babel/node
Now if you open package.json you will see that babel is installed only as a development dependency. Before start using babel we will configure it, just create a file .babelrc with the following content:
{
"presets": ["@babel/preset-env"]
}
Here we are just preparing the Babel transpiling to be suited for specific browsers.

We will also install nodemon to be able automatically to monitor and refresh the nodejs server (loading the new code) when we make changes to our code.
npm i nodemon --save-dev
/* Later we will need  body-parser to be able to parse when receiving as well as send application/json type of requests: npm i body-parser
*/

Now let's change the starting script of package.json to be able to run the upcoming index.js file. We will change it from 'test' to:
start: 'nodemon --exec babel-node index.js" //note the double --
With this change, we now can just type: npm start and it will start recompiled / transpiled version of index.js (using babel) so we can then browse the generated version of index.js via our browser.

In order to be able to browse the output of the index.js file, we will build a server that will serve it. The server will be bound to the localhost IP address and will listen to a specific port.
Create index.js with the following content:
import express from 'express'; // we import the express library
// since we are using babel the import function will be recognized in browsers which are not supporting ES6 imports
const app = express(); // we initiate a class object from the express library
// note the usage of const -> we will not change the app variable later so const is well appropriate to be used here
const PORT = 4000; // let's define a listening port
we will also create our first request route point / :
app.get('/',(req,res) => res.send("server running"));
// basically we say when you have request for the root url / serve them message: "server running"
app.listen(PORT,()=>console.log('listening on ${PORT}));
// here we are just listening to port 4000 and displaying information to the console where the express server starts running.

Now we can just type: npm start and browse inside: http://localhost:4000 to see our application running!

Ok, let's use mongoose to connect to our MongoDB database:
import mongoose from 'mongoose';
then we will connect with the following options:
mongoose.connect(
'mongodb://localhost/my_db',
{
useNewUrlParser: true,
useUnifiedTopology: true
}
);

...
We will proceed with a standard MVC pattern, where we will be having routes that will get browser requests directing them to specific controllers, controllers that will take care of the logic and will use models to perform various actions on the MongoDB database. Index.js will load up everything from a new subdirectory /src/, where our routes, models, and controllers will reside.

Routes
Now it is time to create our routes properly. We will create directory /src/routes/ with file routes.js inside
there we will define and export the routes for our application like so:
const routes = (app)=>{
 app.route('/user')
.get((req,res)=>res.send('Getting information about all users'))
.post((req,res)=>res.send('Creating new user'));
 app.route('/user/:userID')
.get((req,res)=>res.send('Getting specific user by ID'))
.put((req,res)=>res.send('Updating user by ID'))
.delete((req,res)=>res.send('Deleting user by ID'));
}
export default routes;

inside index.js we will import the created routes;
import routes from '/src/routes/routes';
then we will load up those routes with:
routes(app);

Using MongoDB
We will create a schema for of how our documents inside MongoDB we would like to look like, inside the /models/model.js file:
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
export const UserSchema = new Schema(
{
firstName: {type:String,required: 'Enter firstname'},
lastName: {type:String,required: 'Enter lastname'},
email: {type:String,required: 'Enter email'},
created_at: {
type: Date, 
default: Date.now
}
});

Alright, we will use this UserSchema, when gradually creating our controllers.
But before all this, lets recognize requests we will be working with (inside index.js):
// we will be using the built-in middleware functions in Express, so we can parse requests having JSON payloads inside
to parse the request text of type: application/json
app.use(express.json());
and to parse the request text of type application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));

Then we create a directory with file: controllers/controllers.js
import mongoose from 'mongoose';
import {UserSchema} from '../models/model.js'; //so we will be able to use our newly created UserSchema.
const User = mongoose.model('User',UserSchema); // here we create 2 things: 1) User constant which will hold a reference to the User model, 2) which we created from the provided UserSchema.

We will now create our first function that will work with MongoDB and instruct the model to create new User.
export const addNewUser=(req,res)=>{
let newUser = new User(req.body); // we use the whole request body to create a new User model based on the UserSchema.
// Once we have the model we can use its functions such as save, find, findOneAndUpdate and others, which are provided from MongoDB.
newUser.save((err,user)=>{
if (err){res.send(err);} // we send an error if we couldnt create the db document
 res.json(user); // if everything went well, we output the created document as a json format
})
}

now we go back and modify our routes.js to be able to use the newUser function:
1) import addNewUser: import {addNewUser} from 'controller';
2) change .post method to: post(addNewUser);

Next we copy the newUser function and will modify it to create function that will get all of our Users:

export const getUsers=(req,res)=>{
User.find({}(err,users)=>{ // note here we are finding all users via the {} empty search condition, also note that we don't need to create another instance of User, we just use the already created one above.
if (err){res.send(err);}
 res.json(users);
})
}
Now again in routes.js we import the getUsers function, and change the .get method to:
.get((req,res)=>getUsers);
And by the way you can use PostMan to test if the routes are working correctly !

Now for the user/:userID routes:
// we will use mongoDB .findByID() to get specific user by its ID
export const getUserByID=(req,res)=>{
User.findById(req.params.userID, (err,user)=>{ // note here we are getting the  userID from the request parameters
if (err){res.send(err);}
 res.json(users);
})
}
don't forget to update the get method under the '/user/:userID' route in order to activate the getUserByID function: .get(getUserByID)

Let's update some users:
export const updateUser = (req,res) => {
User.findOneAndUpdate(
{_id:req.params.userID}, // here we will be searching first by _id which equals to the passed inside of :userID
req.body, // we pass the request containing the updated information
{new:true, useFindAndModify:false}, // with new:true we will be returning the newly updated user to the res.json
(err,updateduser) =>{
if (err){res.send(err);}
res.json(updateduser); // we send as json the updated user information

});
}

Try to create the deleteUser function by yourself, it will be using the userID parameter just the way updateUser function did. Hint: you can use the .remove() MongoDB function!

Congratulations and enjoy learning !

Subscribe To My Channel for updates

Modernizing old php project with the help of AI

0. Keep docker running in separate outside of VSCODE terminal 1. The importance of GIT for version control - create modernization branch 2. ...