Using Radio Button in React

Using Radio Button in React

Today In this React tutorial, we will explore how to work with Radio buttons in React app. Radio buttons are HTML elements and help the user to choose one option among two or more than two options. In this tutorial, we will learn how to use Radio buttons in React app. Using radio buttons in React is a little bit different than we use in regular HTML. However, we will learn the effortless way to integrate Radio buttons in React.

React Radio Button Example

In this React radio buttons tutorial, we are going to create a basic form in React component using render() method. This form will have five color options, among which a user can choose his favorite color. When a user clicks on the submit button, the radio button state will change.

Basic React App Set Up

Let’s start by installing and setting up the basic React app to show the radio buttons example.

<pre class="ql-syntax" spellcheck="false">npx create-react-app react-radio-buttons </pre>

Enter inside the `react-radio-buttons` project.

<pre class="ql-syntax" spellcheck="false">cd react-radio-buttons </pre>

Run the command to start the React app:

<pre class="ql-syntax" spellcheck="false">npm start </pre>

Define React Radio Button State

Firstly, we will set the radio buttons state. This Radio button state is being referred to as the user’s selection. We set defined the color variable in state and assign the empty (‘ ‘) value in it because the user will choose the color once the form is ready.

<pre class="ql-syntax" spellcheck="false">class App extends Component {

constructor() {
super();

this.state = {
  color: ''
};

}

}
</pre>

Build React Form with React Render Method

In this step, we will define the HTML form with radio buttons along with color values inside the render() method. This method will render 5 Radio buttons wrapped inside the Unordered Lists.

<pre class="ql-syntax" spellcheck="false"> render() {
return (
<div className="App">
<form onSubmit={this.onSubmit}>
<strong>Select Color:</strong>

      &lt;ul&gt;
        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="red"
              checked={this.state.color === "red"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Red&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="green"
              checked={this.state.color === "green"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Green&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="blue"
              checked={this.state.color === "blue"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Blue&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="orange"
              checked={this.state.color === "orange"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Ornage&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="purple"
              checked={this.state.color === "purple"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Purple&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;
      &lt;/ul&gt;

      &lt;button type="submit"&gt;Choose Color&lt;/button&gt;
    &lt;/form&gt;
  &lt;/div&gt;
);

}
</pre>

Let us understand what we did in the form. We defined color values in every radio button along with two properties checked and onChange.

The checked prop in our form is managing the selection of a radio button based on the radio button’s color state.

We are validating every radio buttons state with its respective value. When the value is checked, it will be set to true, and the radio button is considered to be selected. If the value is false, then the radio button will be in the unselected state

How is it working?

Well, when a user clicks on any of the radio buttons from the defined group. Then we are updating the state via color variable using the onChange event handler.

Lastly, we declared the onSubmit event handler and attached with the onSubmit method to the main form. So when the user clicks on the submit button, then the radio buttons value gets updated.

Radio Button Selected State in React

We define the value of a Radio button with the state variable. It sets the selected value of a Radio button in React.

<pre class="ql-syntax" spellcheck="false">class App extends Component {

constructor() {
super();

this.state = {
  color: 'green'
};

}

}
</pre>

It will look something like this in your browser:

Include Event Handler in React Form

In this step, we will include the event handler. This will set and update the sate of Radio button when a user clicks on the radio button.

<pre class="ql-syntax" spellcheck="false"> onRadioChange = (e) => {
this.setState({
color: e.target.value
});
}
</pre>

The above method will update the color value of a Radio button when change by the user.

The Final Touch

In this final step we will define the onSubmit event handler to the form, this event will trigger when a user submits the form.

Use the event.preventDefault() method, it helps in fixes the page redirecting issue when a user clicks on the submit button.

<pre class="ql-syntax" spellcheck="false">import React, { Component } from 'react';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';

class App extends Component {

constructor() {
super();

this.state = {
  color: 'green'
};

this.onRadioChange = this.onRadioChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);

}

onRadioChange = (e) => {
this.setState({
color: e.target.value
});
}

onSubmit = (e) => {
e.preventDefault();
console.log(this.state);
}

render() {
return (
<div className="App">
<form onSubmit={this.onSubmit}>
<strong>Select Color:</strong>

      &lt;ul&gt;
        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="red"
              checked={this.state.color === "red"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Red&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="green"
              checked={this.state.color === "green"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Green&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="blue"
              checked={this.state.color === "blue"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Blue&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="orange"
              checked={this.state.color === "orange"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Ornage&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;label&gt;
            &lt;input
              type="radio"
              value="purple"
              checked={this.state.color === "purple"}
              onChange={this.onRadioChange}
            /&gt;
            &lt;span&gt;Purple&lt;/span&gt;
          &lt;/label&gt;
        &lt;/li&gt;
      &lt;/ul&gt;

      &lt;button type="submit"&gt;Choose Color&lt;/button&gt;
    &lt;/form&gt;
  &lt;/div&gt;
);

}
}

export default App;
</pre>

Following will be the output:

The React Radio button tutorial with example is completed.

Thanks For Visiting, Keep Visiting. If you liked this post, share it with all of your programming buddies!

Further reading

☞ React - The Complete Guide (incl Hooks, React Router, Redux)

☞ Modern React with Redux [2019 Update]

☞ Best 50 React Interview Questions for Frontend Developers in 2019

☞ Best JavaScript Frameworks, Libraries and Tools to Use in 2019

☞ React vs Angular vs Vue.js by Example

Build RESTful API In Laravel 5.8 Example

Build RESTful API In Laravel 5.8 Example


If you want to create web services with php than i will must suggest to use laravel 5.8 to create apis because laravel provide structure with authentication using passport. Based on structure it will become a very easily way to create rest apis.

Just Few days ago, laravel released it's new version as laravel 5.8. As we know laravel is a more popular because of security feature. So many of the developer choose laravel to create rest api for mobile app developing. Yes Web services is a very important when you create web and mobile developing, because you can create same database and work with same data.

Follow bellow few steps to create restful api example in laravel 5.8 app.

Step 1: Download Laravel 5.8

I am going to explain step by step from scratch so, we need to get fresh Laravel 5.8 application using bellow command, So open your terminal OR command prompt and run bellow command:

<pre class="ql-syntax" spellcheck="false">composer create-project --prefer-dist laravel/laravel blog </pre>

Step 2: Install Passport

In this step we need to install passport via the Composer package manager, so one your terminal and fire bellow command:

<pre class="ql-syntax" spellcheck="false">composer require laravel/passport </pre>

After successfully install package, we require to get default migration for create new passport tables in our database. so let's run bellow command.

<pre class="ql-syntax" spellcheck="false">php artisan migrate </pre>

Next, we need to install passport using command, Using passport:install command, it will create token keys for security. So let's run bellow command:

<pre class="ql-syntax" spellcheck="false">php artisan passport:install </pre>

Step 3: Passport Configuration

In this step, we have to configuration on three place model, service provider and auth config file. So you have to just following change on that file.

In model we added HasApiTokens class of Passport,

In AuthServiceProvider we added "Passport::routes()",

In auth.php, we added api auth configuration.

app/User.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Laravel\Passport\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, Notifiable;

/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
protected $fillable = [
    'name', 'email', 'password',
];

/**
 * The attributes that should be hidden for arrays.
 *
 * @var array
 */
protected $hidden = [
    'password', 'remember_token',
];

}
</pre>

app/Providers/AuthServiceProvider.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this-&gt;registerPolicies();

    Passport::routes();
}

}
</pre>

config/auth.php

<pre class="ql-syntax" spellcheck="false"><?php

return [
.....
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
.....
]
</pre>

Step 4: Add Product Table and Model

next, we require to create migration for posts table using Laravel 5.8 php artisan command, so first fire bellow command:

<pre class="ql-syntax" spellcheck="false">php artisan make:migration create_products_table
</pre>

After this command you will find one file in following path database/migrations and you have to put bellow code in your migration file for create products table.

<pre class="ql-syntax" spellcheck="false"><?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('detail');
$table->timestamps();
});
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::dropIfExists('products');
}

}
</pre>

After create migration we need to run above migration by following command:

<pre class="ql-syntax" spellcheck="false">php artisan migrate
</pre>

After create "products" table you should create Product model for products, so first create file in this path app/Product.php and put bellow content in item.php file:


app/Product.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'detail'
];
}
</pre>

Step 5: Create API Routes

In this step, we will create api routes. Laravel provide api.php file for write web services route. So, let's add new route on that file.

routes/api.php

<pre class="ql-syntax" spellcheck="false"><?php

/*
|--------------------------------------------------------------------------

API Routes
Here is where you can register API routes for your application. These
routes are loaded by the RouteServiceProvider within a group which
is assigned the "api" middleware group. Enjoy building your API!

*/

Route::post('register', 'API\[email protected]');

Route::middleware('auth:api')->group( function () {
Route::resource('products', 'API\ProductController');
});
</pre>

Step 6: Create Controller Files

in next step, now we have create new controller as BaseController, ProductController and RegisterController, i created new folder "API" in Controllers folder because we will make alone APIs controller, So let's create both controller:

app/Http/Controllers/API/BaseController.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App\Http\Controllers\API;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller as Controller;

class BaseController extends Controller
{
/**
* success response method.
*
* @return \Illuminate\Http\Response
*/
public function sendResponse($result, $message)
{
$response = [
'success' => true,
'data' => $result,
'message' => $message,
];

    return response()-&gt;json($response, 200);
}

/**
 * return error response.
 *
 * @return \Illuminate\Http\Response
 */
public function sendError($error, $errorMessages = [], $code = 404)
{
	$response = [
        'success' =&gt; false,
        'message' =&gt; $error,
    ];

    if(!empty($errorMessages)){
        $response['data'] = $errorMessages;
    }

    return response()-&gt;json($response, $code);
}

}
</pre>

app/Http/Controllers/API/ProductController.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App\Http\Controllers\API;

use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController as BaseController;
use App\Product;
use Validator;

class ProductController extends BaseController
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$products = Product::all();

    return $this-&gt;sendResponse($products-&gt;toArray(), 'Products retrieved successfully.');
}

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    $input = $request-&gt;all();

    $validator = Validator::make($input, [
        'name' =&gt; 'required',
        'detail' =&gt; 'required'
    ]);

    if($validator-&gt;fails()){
        return $this-&gt;sendError('Validation Error.', $validator-&gt;errors());       
    }

    $product = Product::create($input);

    return $this-&gt;sendResponse($product-&gt;toArray(), 'Product created successfully.');
}

/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function show($id)
{
    $product = Product::find($id);

    if (is_null($product)) {
        return $this-&gt;sendError('Product not found.');
    }

    return $this-&gt;sendResponse($product-&gt;toArray(), 'Product retrieved successfully.');
}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function update(Request $request, Product $product)
{
    $input = $request-&gt;all();

    $validator = Validator::make($input, [
        'name' =&gt; 'required',
        'detail' =&gt; 'required'
    ]);

    if($validator-&gt;fails()){
        return $this-&gt;sendError('Validation Error.', $validator-&gt;errors());       
    }

    $product-&gt;name = $input['name'];
    $product-&gt;detail = $input['detail'];
    $product-&gt;save();

    return $this-&gt;sendResponse($product-&gt;toArray(), 'Product updated successfully.');
}

/**
 * Remove the specified resource from storage.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function destroy(Product $product)
{
    $product-&gt;delete();

    return $this-&gt;sendResponse($product-&gt;toArray(), 'Product deleted successfully.');
}

}
</pre>

app/Http/Controllers/API/RegisterController.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App\Http\Controllers\API;

use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController as BaseController;
use App\User;
use Illuminate\Support\Facades\Auth;
use Validator;

class RegisterController extends BaseController
{
/**
* Register api
*
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
'c_password' => 'required|same:password',
]);

    if($validator-&gt;fails()){
        return $this-&gt;sendError('Validation Error.', $validator-&gt;errors());       
    }

    $input = $request-&gt;all();
    $input['password'] = bcrypt($input['password']);
    $user = User::create($input);
    $success['token'] =  $user-&gt;createToken('MyApp')-&gt;accessToken;
    $success['name'] =  $user-&gt;name;

    return $this-&gt;sendResponse($success, 'User register successfully.');
}

}
</pre>

Now we are ready to to run full restful api and also passport api in laravel. so let's run our example so run bellow command for quick run:

<pre class="ql-syntax" spellcheck="false">php artisan serve
</pre>

make sure in details api we will use following headers as listed bellow:

<pre class="ql-syntax" spellcheck="false">'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
]
</pre>

Here is Routes URL with Verb:

1) Login: Verb:GET, URL:http://localhost:8000/oauth/token

2) Register: Verb:GET, URL:http://localhost:8000/api/register

3) List: Verb:GET, URL:http://localhost:8000/api/products

4) Create: Verb:POST, URL:http://localhost:8000/api/products

5) Show: Verb:GET, URL:http://localhost:8000/api/products/{id}

6) Update: Verb:PUT, URL:http://localhost:8000/api/products/{id}

7) Delete: Verb:DELETE, URL:http://localhost:8000/api/products/{id}

Now simply you can run above listed url like as bellow screen shot:

Login API:

Register API:

Product List API:

Product Create API:

Product Show API:

Product Update API:

Product Delete API:

I hope it can help you...

Thanks for reading ❤

If you liked this post, share it with all of your programming buddies!

Follow me on Facebook | Twitter

Learn More

PHP with Laravel for beginners - Become a Master in Laravel

Projects in Laravel: Learn Laravel Building 10 Projects

Laravel for RESTful: Build Your RESTful API with Laravel

Fullstack Web Development With Laravel and Vue.js

Creating RESTful APIs with NodeJS and MongoDB Tutorial

Developing RESTful APIs with Lumen (A PHP Micro-framework)

Build a Simple REST API in PHP

Node.js and Express Tutorial: Building and Securing RESTful APIs

Building a Vue SPA With Laravel

Build a CMS with Laravel and Vue

Angular 8 Pagination Example and Tutorial

Angular 8 Pagination Example and Tutorial

For example, when you search something that returns a large number of records which cannot be shown on a single web page therefore, those records are part into number of pages that can be accessed through links via pagination structure.

So today in this demo we will discuss the simple pagination in Angular 8.

Step 1: Create a basic app with angular cli

<pre class="ql-syntax" spellcheck="false">ng new angular8-simple-pagination-example </pre>

By typing the above command we will see a basic angular app created on the current folder. So move to the created folder by typing cd angular8-simple-pagination-example/. You can check the newly created app by typing <a href="http://localhost:4200" title="" target="_blank">http://localhost:4200</a> on the browser.

Step 2: install ngx-pagination pagination dependency from terminal

So run the below command over terminal

<pre class="ql-syntax" spellcheck="false">npm install ngx-pagination --save </pre>

Step 3: Create dummy records for pagination

Now we will create static data to show the pagination. So lets have a look on the code under file app.component.ts 

<pre class="ql-syntax" spellcheck="false">import { Component } from '@angular/core'; import {NgxPaginationModule} from 'ngx-pagination'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'simple pagination demo'; collection = []; constructor(){ for(let i=1;i<=100;i++){ let Obj = {'name': `Employee Name ${i}`,'code': `EMP00 ${i}`} this.collection.push(Obj); } } } </pre>

In the above file, we can see that inside constructor we have created a loop for created dummy record for 100 employees having employee name & code for showing pagination.

Step 4: Import dependency in app.module.ts

Now let's have a look on the code inside app.module.ts where the ngx-pagination module has been imported

<pre class="ql-syntax" spellcheck="false">import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core';   import { NgxPaginationModule } from 'ngx-pagination'; import { AppComponent } from './app.component';   @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, NgxPaginationModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } </pre>

Step 5: Update view from app.component.html

Now one last step needed to do is, add the below code anywhere inside app.component.html

<pre class="ql-syntax" spellcheck="false"><ul> <li> Emp Name | Emp code</li> <li *ngFor="let item of collection | paginate:{itemsPerPage: 5, currentPage:p}"> {{item.name}} | {{item.code}}</li>  </ul> <pagination-controls (pageChange)="p=$event"></pagination-controls> </pre>

Now, we are done with all the needed steps for the pagination in our angular application. 

 

Step 6: Run the app

Run the app over the terminal with npm start and check the app after typing the url <a href="http://localhost:4200/." target="_blank">http://localhost:4200/.</a> A page will open like below:

Conclusion

By following these easy steps we can easily achieve the client side pagination in Angular 8 application. If you want to impliment server side pagination in angular8 <a href="https://jsonworld.com/demo/server-side-pagination-in-angular-example-and-tutorial" title="" target="_blank">Server Side Pagination in Angular Example and Tutorial</a> . You can also find other demos of<a href="https://jsonworld.com/demo/angular-sample-projects" title="" target="_blank"> Angular Sample Application</a> here to start working on enterprise level application. <a href="https://www.npmjs.com/package/ngx-pagination" title="" target="_blank">Click here</a> to view more about the pagination package over npm.

Originally published by Suraj Roy at jsonworld.com

==========================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on <a href="https://www.facebook.com/angular4u" title="" target="_blank">Facebook</a> | <a href="https://twitter.com/codek_tv" title="" target="_blank">Twitter</a>

Learn More

☞ <a href="http://learnstartup.net/p/H1jE_tD3l" title="" target="_blank">Angular 8 (formerly Angular 2) - The Complete Guide</a>

☞ <a href="http://learnstartup.net/p/HJigQzgZx" title="" target="_blank">Learn and Understand AngularJS</a>

☞ <a href="http://learnstartup.net/p/ry7Ey9yKW" title="" target="_blank">The Complete Angular Course: Beginner to Advanced</a>

☞ <a href="http://learnstartup.net/p/rkjpGfa5W" title="" target="_blank">Angular Crash Course for Busy Developers</a>

☞ <a href="http://learnstartup.net/p/SkdU19JFZ" title="" target="_blank">Angular Essentials (Angular 2+ with TypeScript)</a>

☞ <a href="http://learnstartup.net/p/B1oHaY8cM" title="" target="_blank">Angular (Full App) with Angular Material, Angularfire & NgRx</a>

☞ <a href="https://l.morioh.com/b0a3f595aa?r=http://learnstartup.net/p/Skf7ILFw3l" title="" target="_blank">Angular & NodeJS - The MEAN Stack Guide</a>

Angular Architecture Patterns and Best Practices (that help to scale)

Angular Architecture Patterns and Best Practices (that help to scale)
<p class="ql-align-center">Originally published by Bartosz Pietrucha at angular-academy.com</p><p> In order to deal with mentioned factors to maintain a high quality of delivery and prevent technical debt, robust and well-grounded architecture is necessary. Angular itself is a quite opinionated framework, forcing developers to do things the proper way, yet there are a lot of places where things can go wrong. In this article, I will present high-level recommendations of well-designed Angular application architecture based on best practices and battle-proven patterns. Our ultimate goal in this article is to learn how to design Angular application in order to maintain sustainable development speed and ease of adding new features in the long run. To achieve these goals, we will apply:</p>
    <li>proper abstractions between application layers,</li><li>unidirectional data flow,</li><li>reactive state management,</li><li>modular design,</li><li>smart and dumb components pattern.</li>
<p></p>

Problems of scalability in front-end

<p>Let's think about problems in terms of scalability we can face in the development of modern front-end applications. Today, front-end applications are not "just displaying" data and accepting user inputs. Single Page Applications (SPAs) are providing users with rich interactions and use backend mostly as a data persistence layer. This means, far more responsibility has been moved to the front-end part of software systems. This leads to a growing complexity of front-end logic, we need to deal with. Not only the number of requirements grows over time, but the amount of data we load into the application is increasing. On top of that, we need to maintain application performance, which can easily be hurt. Finally, our development teams are growing (or at least rotating - people come and go) and it is important for new-comers to get up to speed as fast as possible.</p><p></p><p>One of the solutions to the problems described above is solid system architecture. But, this comes with the cost, the cost of investing in that architecture from day one. It can be very tempting for us developers, to deliver new features very quickly, when the system is still very small. At this stage, everything is easy and understandable, so development goes really fast. But, unless we care about the architecture, after a few developers rotations, tricky features, refactorings, a couple of new modules, the speed of development slows down radically. Below diagram presents how it usually looked like in my development career. This is not any scientifical study, it's just how I see it.</p><p></p>

Software architecture

<p>To discuss architecture best practices and patterns, we need to answer a question, what the software architecture is, in the first place. Martin Fowlerdefines architecture as "highest-level breakdown of a system into its parts". On top of that, I would say that software architecture describes how the software is composed of its parts and what are the rules and constraints of the communication between those parts. Usually, the architectural decisions that we make in our system development, are hard to change as the system grows over time. That's why it is very important to pay attention to those decisions from the very beginning of our project, especially if the software we build is supposed to be running in production for many years. Robert C. Martin once said: the true cost of software is its maintenance. Having well-grounded architecture helps to reduce the costs of the system's maintenance.</p>
Software architecture is the way the software is composed of its parts and the rules and constraints of the communication between those parts

High-level abstraction layers

<p>The first way, we will be decomposing our system, is through the abstraction layers. Below diagram depicts the general concept of this decomposition. The idea is to place the proper responsibility into the proper layer of the system: coreabstraction or presentation layer. We will be looking at each layer independently and analyzing its responsibility. This division of the system also dictates communication rules. For example, the presentation layer can talk to the core layer only through the abstractionlayer. Later, we will learn what are the benefits of this kind of constraint.</p><p></p>

Presentation layer

<p>Let's start analyzing our system break-down from the presentation layer. This is the place where all our Angular components live. The only responsibilities of this layer are to present and to delegate. In other words, it presents the UI and delegates user's actions to the core layer, through the abstraction layer. It knows what to display and what to do, but it does not know how the user's interactions should be handled.</p><p>Below code snippet contains CategoriesComponent using SettingsFacadeinstance from abstraction layer to delegate user's interaction (via addCategory() and updateCategory()) and present some state in its template (via isUpdating$).</p><pre class="ql-syntax" spellcheck="false">@Component({ selector: 'categories', templateUrl: './categories.component.html', styleUrls: ['./categories.component.scss'] }) export class CategoriesComponent implements OnInit {

@Input() cashflowCategories$: CashflowCategory[];
newCategory: CashflowCategory = new CashflowCategory();
isUpdating$: Observable<boolean>;

constructor(private settingsFacade: SettingsFacade) {
this.isUpdating$ = settingsFacade.isUpdating$();
}

ngOnInit() {
this.settingsFacade.loadCashflowCategories();
}

addCategory(category: CashflowCategory) {
this.settingsFacade.addCashflowCategory(category);
}

updateCategory(category: CashflowCategory) {
this.settingsFacade.updateCashflowCategory(category);
}

}
</pre>

Abstraction layer

<p>The abstraction layer decouples the presentation layer from the core layer and also has it's very own defined responsibilities. This layer exposes the streams of state and interface for the components in the presentation layer, playing the role of the facade. This kind of facade sandboxes what components can see and do in the system. We can implement facades by simply using Angular class providers. The classes here may be named with Facade postfix, for example SettingsFacade. Below, you can find an example of such a facade.</p><pre class="ql-syntax" spellcheck="false">@Injectable()
export class SettingsFacade {

constructor(private cashflowCategoryApi: CashflowCategoryApi, private settingsState: SettingsState) { }

isUpdating$(): Observable<boolean> {
return this.settingsState.isUpdating$();
}

getCashflowCategories$(): Observable<CashflowCategory[]> {
// here we just pass the state without any projections
// it may happen that it is necessary to combine two or more streams and expose to the components
return this.settingsState.getCashflowCategories$();
}

loadCashflowCategories() {
return this.cashflowCategoryApi.getCashflowCategories()
.pipe(tap(categories => this.settingsState.setCashflowCategories(categories)));
}

// optimistic update
// 1. update UI state
// 2. call API
addCashflowCategory(category: CashflowCategory) {
this.settingsState.addCashflowCategory(category);
this.cashflowCategoryApi.createCashflowCategory(category)
.subscribe(
(addedCategoryWithId: CashflowCategory) => {
// success callback - we have id generated by the server, let's update the state
this.settingsState.updateCashflowCategoryId(category, addedCategoryWithId)
},
(error: any) => {
// error callback - we need to rollback the state change
this.settingsState.removeCashflowCategory(category);
console.log(error);
}
);
}

// pessimistic update
// 1. call API
// 2. update UI state
updateCashflowCategory(category: CashflowCategory) {
this.settingsState.setUpdating(true);
this.cashflowCategoryApi.updateCashflowCategory(category)
.subscribe(
() => this.settingsState.updateCashflowCategory(category),
(error) => console.log(error),
() => this.settingsState.setUpdating(false)
);
}
}
</pre>

Abstraction interface

<p>We already know the main responsibilities for this layer; to expose streams of state and interface for the components. Let's start with the interface. Public methods loadCashflowCategories()addCashflowCategory() and updateCashflowCategory() abstract away the details of state management and the external API calls from the components. We are not using API providers (like CashflowCategoryApi) in components directly, as they live in the core layer. Also, how the state changes is not a concern of the components. The presentation layer should not care about how things are done and components should just call the methods from the abstraction layer when necessary (delegate). Looking at the public methods in our abstraction layer should give us a quick insight about high-level use casesin this part of the system.</p><p>But we should remember that the abstraction layer is not a place to implement business logic. Here we just want to connect the presentation layer to our business logic, abstracting the way it is connected.</p>

State

<p>When it comes to the state, the abstraction layer makes our components independent of the state management solution. Components are given Observables with data to display on the templates (usually with async pipe) and don't care how and where this data comes from. To manage our state we can pick any state management library that supports RxJS (like NgRx) or simple use BehaviorSubjects to model our state. In the example above we are using state object that internally uses BehaviorSubjects (state object is a part of our core layer). In the case of NgRx, we would dispatch actions for the store.</p><p>Having this kind abstraction gives us a lot of flexibility and allows to change the way we manage state not even touching the presentation layer. It's even possible to seamlessly migrate to a real-time backend like Firebase, making our application real-time. I personally like to start with BehaviorSubjects to manage the state. If later, at some point in the development of the system, there is a need to use something else, with this kind of architecture, it is very easy to refactor.</p>

Synchronization strategy

<p>Now, let's take a closer look at the other important aspect of the abstraction layer. Regardless of the state management solution we choose, we can implement UI updates in either optimistic or pessimistic fashion. Imagine we want to create a new record in the collection of some entities. This collection was fetched from the backend and displayed in the DOM. In a pessimistic approach, we first try to update the state on the backend side (for example with HTTP request) and in case of success we update the state in the frontend application. On the other hand, in an optimistic approach, we do it in a different order. First, we assume that the backend update will succeed and update frontend state immediately. Then we send request to update server state. In case of success, we don't need to do anything, but in case of failure, we need to rollback the change in our frontend application and inform the user about this situation.</p>
Optimistic update changes the UI state first and attempts to update the backend state. This provides a user with a better experience, as he does not see any delays, because of network latency. If backend update fails, then UI change has to be rolled back.
Pessimistic update changes the backend state first and only in case of success updates the UI state. Usually, it is necessary to show some kind of spinner or loading bar during the execution of backend request, because of network latency.

Caching

<p>Sometimes, we may decide that the data we fetch from the backend will not be a part of our application state. This may be useful for read-only data that we don't want to manipulate at all and just pass (via abstraction layer) to the components. In this case, we can apply data caching in our facade. The easiest way to achieve it is to use shareReplay() RxJS operator that will replay the last value in the stream for each new subscriber. Take a look at the code snippet below with RecordsFacade using RecordsApi to fetch, cache and filter the data for the components.</p><pre class="ql-syntax" spellcheck="false">@Injectable()
export class RecordsFacade {

private records$: Observable<Record[]>;

constructor(private recordApi: RecordApi) {
this.records$ = this.recordApi
.getRecords()
.pipe(shareReplay(1)); // cache the data
}

getRecords() {
return this.records$;
}

// project the cached data for the component
getRecordsFromPeriod(period?: Period): Observable<Record[]> {
return this.records$
.pipe(map(records => records.filter(record => record.inPeriod(period))));
}

searchRecords(search: string): Observable<Record[]> {
return this.recordApi.searchRecords(search);
}
}
</pre><p>To sum up, what we can do in the abstraction layer is to:</p>

    <li>expose methods for the components in which we:</li><li class="ql-indent-1">delegate logic execution to the core layer,</li><li class="ql-indent-1">decide about data synchronization strategy (optimistic vs. pessimistic),</li><li>expose streams of state for the components:</li><li class="ql-indent-1">pick one or more streams of UI state (and combine them if necessary),</li><li class="ql-indent-1">cache data from external API.</li>
<p>As we see, the abstraction layer plays an important role in our layered architecture. It has clearly defined responsibilities what helps to better understand and reason about the system. Depending on your particular case, you can create one facade per Angular module or one per each entity. For example, the SettingsModule may have a single SettingsFacade, if it's not too bloated. But sometimes it may be better to create more-granular abstraction facades for each entity individually, like UserFacade for Userentity.</p>

Core layer

<p>The last layer is the core layer. Here is where core application logic is implemented. All data manipulation and outside world communicationhappen here. If for state management, we were using a solution like NgRx, here is a place to put our state definition, actions and reducers. Since in our examples we are modeling state with BehaviorSubjects, we can encapsulate it in a convenient state class. Below, you can find SettingsState example from the core layer.</p><pre class="ql-syntax" spellcheck="false">@Injectable()
export class SettingsState {

private updating$ = new BehaviorSubject<boolean>(false);
private cashflowCategories$ = new BehaviorSubject<CashflowCategory[]>(null);

isUpdating$() {
return this.updating$.asObservable();
}

setUpdating(isUpdating: boolean) {
this.updating$.next(isUpdating);
}

getCashflowCategories$() {
return this.cashflowCategories$.asObservable();
}

setCashflowCategories(categories: CashflowCategory[]) {
this.cashflowCategories$.next(categories);
}

addCashflowCategory(category: CashflowCategory) {
const currentValue = this.cashflowCategories$.getValue();
this.cashflowCategories$.next([...currentValue, category]);
}

updateCashflowCategory(updatedCategory: CashflowCategory) {
const categories = this.cashflowCategories$.getValue();
const indexOfUpdated = categories.findIndex(category => category.id === updatedCategory.id);
categories[indexOfUpdated] = updatedCategory;
this.cashflowCategories$.next([...categories]);
}

updateCashflowCategoryId(categoryToReplace: CashflowCategory, addedCategoryWithId: CashflowCategory) {
const categories = this.cashflowCategories$.getValue();
const updatedCategoryIndex = categories.findIndex(category => category === categoryToReplace);
categories[updatedCategoryIndex] = addedCategoryWithId;
this.cashflowCategories$.next([...categories]);
}

removeCashflowCategory(categoryRemove: CashflowCategory) {
const currentValue = this.cashflowCategories$.getValue();
this.cashflowCategories$.next(currentValue.filter(category => category !== categoryRemove));
}
}
</pre><p>In the core layer, we also implement HTTP queries in the form of class providers. This kind of class could have Api or Service name postfix. API services have only one responsibility - it is just to communicate with API endpoints and nothing else. We should avoid any caching, logic or data manipulation here. A simple example of API service can be found below.</p><pre class="ql-syntax" spellcheck="false">@Injectable()
export class CashflowCategoryApi {

readonly API = '/api/cashflowCategories';

constructor(private http: HttpClient) {}

getCashflowCategories(): Observable<CashflowCategory[]> {
return this.http.get<CashflowCategory[]>(this.API);
}

createCashflowCategory(category: CashflowCategory): Observable<any> {
return this.http.post(this.API, category);
}

updateCashflowCategory(category: CashflowCategory): Observable<any> {
return this.http.put(${this.API}/${category.id}, category);
}

}
</pre><p>In this layer, we could also place any validators, mappers or more advanced use-cases that require manipulating many slices of our UI state.</p><p>We have covered the topic of the abstraction layers in our frontend application. Every layer has it's well-defined boundaries and responsibilities. We also defined the strict rules of communication between layers. This all helps to better understand and reason about the system over time as it becomes more and more complex.</p><p></p><p>If you need help with your project, check out Angualar Academy Workshops or write an email to [email protected].</p>

Unidirectional data flow and reactive state management

<p>The next principle we want to introduce in our system is about the data flow and propagation of change. Angular itself uses unidirectional data flow on presentation level (via input bindings), but we will impose a similar restriction on the application level. Together with reactive state management (based on streams), it will give us the very important property of the system - data consistency. Below diagram presents the general idea of unidirectional data flow.</p><p></p><p>Whenever any model value change in our application, Angular change detection system takes care of the propagation of that change. It does it via input property bindings from the top to bottom of the whole component tree. It means that a child component can only depend on its parent and never vice versa. This is why we call it unidirectional data flow. This allows Angular to traverse the components tree only once (as there are no cycles in the tree structure) to achieve a stable state, which means that every value in the bindings is propagated.</p><p>As we know from previous chapters, there is the core layer above the presentation layer, where our application logic is implemented. There are the services and providers that operate on our data. What if we apply the same principle of data manipulation on that level? We can place the application data (the state) in one place "above" the components and propagate the values down to the components via Observable streams (Redux and NgRx call this place a store). The state can be propagated to multiple components and displayed in multiple places, but never modified locally. The change may come only "from above" and the components below only "reflect" the current state of the system. This gives us the important system's property mentioned before - data consistency - and the state object becomes the single source of truth. Practically speaking, we can display the same data in multiple places and not be afraid that the values would differ.</p><p>Our state object exposes the methods for the services in our core layer to manipulate the state. Whenever there is a need to change the state, it can happen only by calling a method on the state object (or dispatching an action in case of using NgRx). Then, the change is propagated "down", via streams, the to presentation layer (or any other service). This way, our state management is reactive. Moreover, with this approach, we also increase the level of predictability in our system, because of strict rules of manipulating and sharing the application state. Below you can find a code snippet modeling the state with BehaviorSubjects.</p><pre class="ql-syntax" spellcheck="false">@Injectable()
export class SettingsState {

private updating$ = new BehaviorSubject<boolean>(false);
private cashflowCategories$ = new BehaviorSubject<CashflowCategory[]>(null);

isUpdating$() {
return this.updating$.asObservable();
}

setUpdating(isUpdating: boolean) {
this.updating$.next(isUpdating);
}

getCashflowCategories$() {
return this.cashflowCategories$.asObservable();
}

setCashflowCategories(categories: CashflowCategory[]) {
this.cashflowCategories$.next(categories);
}

addCashflowCategory(category: CashflowCategory) {
const currentValue = this.cashflowCategories$.getValue();
this.cashflowCategories$.next([...currentValue, category]);
}

updateCashflowCategory(updatedCategory: CashflowCategory) {
const categories = this.cashflowCategories$.getValue();
const indexOfUpdated = categories.findIndex(category => category.id === updatedCategory.id);
categories[indexOfUpdated] = updatedCategory;
this.cashflowCategories$.next([...categories]);
}

updateCashflowCategoryId(categoryToReplace: CashflowCategory, addedCategoryWithId: CashflowCategory) {
const categories = this.cashflowCategories$.getValue();
const updatedCategoryIndex = categories.findIndex(category => category === categoryToReplace);
categories[updatedCategoryIndex] = addedCategoryWithId;
this.cashflowCategories$.next([...categories]);
}

removeCashflowCategory(categoryRemove: CashflowCategory) {
const currentValue = this.cashflowCategories$.getValue();
this.cashflowCategories$.next(currentValue.filter(category => category !== categoryRemove));
}
}

</pre><p>Let's recap the steps of handling the user interaction, having in mind all the principles we have already introduced. First, let's imagine that there is some event in the presentation layer (for example button click). The component delegates the execution to the abstraction layer, calling the method on the facade settingsFacade.addCategory(). Then, the facade calls the methods on the services in the core layer - categoryApi.create() and settingsState.addCategory(). The order of invocation of those two methods depends on synchronization strategy we choose (pessimistic or optimistic). Finally, the application state is propagated down to the presentation layer via the observable streams. This process is well-defined.</p><p></p>

Modular design

<p>We have covered the horizontal division in our system and the communication patterns across it. Now we are going to introduce a vertical separation into feature modules. The idea is to slice the application into feature modules representing different business functionalities. This is yet another step to deconstruct the system into smaller pieces for better maintainability. Each of the features modules share the same horizontal separation of the core, abstraction, and presentation layer. It is important to note, that these modules could be lazily loaded (and preloaded) into the browser increasing the initial load time of the application. Below you can find a diagram illustrating features modules separation.</p><p></p><p>Our application has also two additional modules for more technical reasons. We have a CoreModule that defines our singleton services, single-instance components, configuration, and export any third-party modules needed in AppModule. This module is imported only once in AppModule. The second module is SharedModule that contains common components/pipes/directives and also export commonly used Angular modules (like CommonModule). SharedModule can be imported by any feature module. The diagram below presents the imports structure.</p><p></p>

Module directory structure

<p>Below diagram presents how we can place all the pieces of our SettingsModule inside the directories. We can put the files inside of the folders with a name representing their function.</p><p></p>

Smart and dumb components

<p>The final architectural pattern we introduce in this article is about components themselves. We want to divide components into two categories, depending on their responsibilities. First, are the smart components (aka containers). These components usually:</p>
    <li>have facade/s and other services injected,</li><li>communicate with the core layer,</li><li>pass data to the dumb components,</li><li>react to the events from dumb components,</li><li>are top-level routable components (but not always!).</li>
<p>Previously presented CategoriesComponent is smart. It has SettingsFacadeinjected and uses it to communicate with the core layer of our application.</p><p>In the second category, there are dumb components (aka presentational). Their only responsibilities are to present UI element and to delegate user interaction "up" to the smart components via events. Think of a native HTML element like <button>Click me</button>. That element does not have any particular logic implemented. We can think of the text 'Click me' as an input for this component. It also has some events that can be subscribed to, like click event. Below you can find a code snippet of a simple presentational component with one input and no output events.</p><pre class="ql-syntax" spellcheck="false">@Component({
selector: 'budget-progress',
templateUrl: './budget-progress.component.html',
styleUrls: ['./budget-progress.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class BudgetProgressComponent {

@Input()
budget: Budget;
today: string;

}
</pre>

Summary

<p>We have covered a couple of ideas on how to design the architecture of an Angular application. These principles, if applied wisely, can help to maintain sustainable development speed over time, and allow new features to be delivered easily. Please don't treat them as some strict rules, but rather recommendations that could be employed when they make sense.</p><p>We have taken a close look at the abstractions layers, unidirectional data flow, and reactive state management, modular design, and smart/dumb components pattern. I hope that these concepts will be helpful in your projects and, as always, if you have any questions, I am more than happy to chat with you.</p><p class="ql-align-center">Originally published by Bartosz Pietrucha at angular-academy.com</p><p>==========================================</p><p>Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter</p>

Learn More

<p>☞ Angular 8 (formerly Angular 2) - The Complete Guide</p><p>☞ Complete Angular 8 from Zero to Hero | Get Hired</p><p>☞ Learn and Understand AngularJS</p><p>☞ The Complete Angular Course: Beginner to Advanced</p><p>☞ Angular Crash Course for Busy Developers</p><p>☞ Angular Essentials (Angular 2+ with TypeScript)</p><p>☞ Angular (Full App) with Angular Material, Angularfire & NgRx</p><p>☞ Angular & NodeJS - The MEAN Stack Guide</p>

Keeping your JavaScript code clean forever and scalable

Keeping your JavaScript code clean forever and scalable

JavaScript has its origins in the early web. Starting out as a scripting language, it has now evolved into a fully fledged programming language with support for server-side execution.

Modern web applications rely heavily on JavaScript, especially single-page applications (SPAs). With emerging frameworks like React, AngularJS, and Vue.js, web apps are mainly built with JavaScript.

Scaling these applications — frontend equally as backend — can be quite tricky. With a mediocre setup, you will eventually hit limitations and get lost in a sea of confusion. I want to share a couple of small tips that will help you write clean code in an efficient way.

This article is geared towards JavaScript developers of any skill level. However, developers with at least intermediate knowledge of JavaScript will benefit most from these tips.


1. Isolate your code

The most important thing I can recommend to keep a codebase clean and readable is having specific chunks of logic (usually functions) separated by topic. If you write a function, the function should default to having only one purpose and should not do multiple things at once.

Also, you should avoid causing side effects, meaning in most cases, you should not change anything that is declared outside your function. You receive data into functions with parameters; everything else should not be accessed. If you wish to get something out of the function, return new values.

2. Modularization

Of course, you can group multiple functions into one module (and/or class, if you wish) if these functions are used in a similar way or do similar things. For example, if you have many different calculations to do, split them up into isolated steps (functions) that you can chain. However, these functions can all be declared in one file (module). Here is the example in JavaScript:

function add(a, b) {
    return a + b   
}

function subtract(a, b) {
    return a - b   
}

module.exports = {
    add,
    subtract
}

const { add, subtract } = require('./calculations')

console.log(subtract(5, add(3, 2))

If you are writing frontend JavaScript, definitely make use of default exports for the most important items and named exports for secondary items.

3. Prefer multiple parameters over single object parameters

When declaring a function, you should always prefer multiple parameters over one parameter that expects an object:

// GOOD
function displayUser(firstName, lastName, age) {
    console.log(`This is ${firstName} ${lastName}. She is ${age} years old.`)
}

// BAD
function displayUser(user) {
    console.log(`This is ${user.firstName} ${user.lastName}. She is ${user.age} years old.`)
}

The reason behind this is that you know exactly what you need to pass to the function when you look at the first line of the function declaration.

Even though functions should be limited in size — doing only one job — it may happen that functions grow bigger in size. Scanning through the function body for the variables you need to pass (that are nested inside an object) will take you more time. Sometimes it might seem easier to just use the whole object and pass it to the function, but to scale your application, this setup will definitely help.

There is a certain point where declaring specific parameters does not make sense. For me, it is above four or five function parameters. If your function grows that big, you should pivot to use object parameters.

The main reason here is that parameters need to be passed in a specific order. If you have optional parameters, you need to   pass undefined or null. With object parameters, you can simply pass the whole object, where order and undefined values do not matter.

4. Destructuring

Destructuring is a nice tool that was introduced with ES6. It lets you grab specific fields from an object and assign it to a variable immediately. You can use this for any kind of object or module.

// EXAMPLE FOR MODULES
const { add, subtract } = require('./calculations')

It does make sense to only import the functions you need to use in your file instead of the whole module, and then access the specific functions from it. Similarly, when you decide that you definitely need an object as function parameter, use destructuring as well. This will still give you the overview of what is needed inside the function:

function logCountry({name, code, language, currency, population, continent}) {
    let msg = `The official language of ${name} `
    if(code) msg += `(${code}) `
    msg += `is ${language}. ${population} inhabitants pay in ${currency}.`
    if(contintent) msg += ` The country is located in ${continent}`
}

logCountry({
    name: 'Germany',
    code: 'DE',
    language 'german',
    currency: 'Euro',
    population: '82 Million',
})

logCountry({
    name: 'China',
    language 'mandarin',
    currency: 'Renminbi',
    population: '1.4 Billion',
    continent: 'Asia',
})

As you can see, I still know what I need to pass to the function — even if it is wrapped in an object. To solve the problem of knowing what is required, see the next tip!

(By the way, this also works for React functional components.)

5. Use default values

Default values for destructuring or even basic function parameters are very useful. Firstly, they give you an example of what value you can pass to the function. Secondly, you can indicate which values are required and which are not. Using the previous example, the full setup for the function could look like this:

function logCountry({
    name = 'United States', 
    code, 
    language = 'English', 
    currency = 'USD', 
    population = '327 Million', 
    continent,
}) {
    let msg = `The official language of ${name} `
    if(code) msg += `(${code}) `
    msg += `is ${language}. ${population} inhabitants pay in ${currency}.`
    if(contintent) msg += ` The country is located in ${continent}`
}

logCountry({
    name: 'Germany',
    code: 'DE',
    language 'german',
    currency: 'Euro',
    population: '82 Million',
})


logCountry({
    name: 'China',
    language 'mandarin',
    currency: 'Renminbi',
    population: '1.4 Billion',
    continent: 'Asia',
})

Obviously, sometimes you might not want to use default values and instead throw an error if you do not pass a value. Oftentimes, however, this is a handy trick.

6. Data scarcity

The previous tips lead us to one conclusion: do not pass around data that you don’t need. Here, again, it might mean a bit more work when setting up your functions. In the long run, however, it will definitely give you a more readable codebase. It is invaluable to know exactly which values are used in a specific spot.

7. Line and indentation limit

I have seen big files — very big files. In fact, over 3,000 lines of code. Finding chunks of logic is incredibly hard in these files.

Therefore, you should limit your file size to a certain number of lines. I tend to keep my files below 100 lines of code. Sometimes, it is hard to break up files, and they will grow to 200–300 lines and, in rare occasions, up to 400.

Above this threshold, the file gets too cluttered and hard to maintain. Feel free to create new modules and folders. Your project should look like a forest, consisting of trees (module sections) and branches (groups of modules and module files). Avoid trying to mimic the Alps, piling up code in confined areas.

Your actual files, in comparison, should look like the Shire, with some hills (small levels of indentation) here and there, but everything relatively flat. Try to keep the level of indentation below four.

Maybe it is helpful to enable eslint-rules for these tips!

8. Use prettier

Working in a team requires a clear style guide and formatting. ESLint offers a huge ruleset that you can customize to your needs. There is also eslint --fix, which corrects some of the errors, but not all.

Instead, I recommend using Prettier to format your code. That way, developers do not have to worry about code formatting, but simply writing high-quality code. The appearance will be consistent and the formatting automatic.

9. Use meaningful variable names

Ideally, a variable should be named based on its content. Here are some guidelines that will help you declare meaningful variable names.

Functions

Functions usually perform some kind of action. To explain that, humans use verbs — convert or display, for example. It is a good idea to name your functions with a verb in the beginning, e.g., convertCurrency or displayUserName.

Arrays

These will usually hold a list of items; therefore, append an s to your variable name. For example:

const students = ['Eddie', 'Julia', 'Nathan', 'Theresa']

Booleans

Simply start with is or has to be close to natural language. You would ask something like, “Is that person a teacher?” → “Yes” or “No.” Similarly:

const isTeacher = true // OR false

Array functions

forEachmapreducefilter, etc. are great native JavaScript functions to handle arrays and perform some actions. I see a lot of people simply passing el or element as a parameter to the callback functions. While this is easy and quick, you should also name these according to their value. For example:

const cities = ['Berlin', 'San Francisco', 'Tel Aviv', 'Seoul']
cities.forEach(function(city) {
...
})

IDs

Oftentimes, you have to keep track of the ids of specific datasets and objects. When ids are nested, simply leave it as id. Here, I like to map MongoDB _id to simply id before returning the object to the frontend. When extracting ids from an object, prepend the type of the object. For example:

const studentId = student.id
// OR
const { id: studentId } = student // destructuring with renaming

An exception to that rule is MongoDB references in models. Here, simply name the field after the referenced model. This will keep things clear when populating references documents:

const StudentSchema = new Schema({
    teacher: {
        type: Schema.Types.ObjectId,
        ref: 'Teacher',
        required: true,
    },
    name: String,
    ...
})

10. Use async / await where possible

Callbacks are the worst when it comes to readability — especially when nested. Promises were a nice improvement, but async/await has the best readability, in my opinion. Even for beginners, or people coming from other languages, this will help a lot. However, make sure you understand the concept behind it and do not mindlessly use it everywhere.

11. Module import order

As we saw in tips 1 and 2, keeping logic in the right place is key to maintainability. In the same way, how you import different modules can reduce confusion in your files. I follow a simple structure when importing different modules:

// 3rd party packages
import React from 'react'
import styled from 'styled-components'

// Stores
import Store from '~/Store'

// reusable components
import Button from '~/components/Button'

// utility functions
import { add, subtract } from '~/utils/calculate'

// submodules
import Intro from './Intro'
import Selector from './Selector'

I used a React component as an example here since there are more types of imports. You should be able to adapt that to your specific use case.

12. Get rid of console

console.log is a nice way of debugging — very simple, quick, and does the job. Obviously, there are more sophisticated tools, but I think every developer still uses it. If you forget to clean up logs, your console will eventually end up a giant mess. Then there is logs that you actually want to keep in your codebase; for example, warning and errors.

To solve this issue, you can still use console.log for debugging reasons, but for lasting logs, use a library like loglevel or winston. Additionally, you can warn for console statements with ESLint. That way you can easily globally look for console... and remove these statements.


Cool, isn’t it?

Following these guidelines help to Keep your JavaScript code clean forever and scalable. Are there any tips you find particularly useful? Let us know in the comments what you will include in your coding workflow, and please share any other tips you use to help with code structure!

Thanks for reading, Keep visiting. Hope this post will surely help and you! Please share if you liked it!

Related Articles: Keeping your Vue.js code Clean

Laravel 5.8 Tutorial - How to build user roles and permissions on Laravel 5.8 App

Laravel 5.8 Tutorial - How to build user roles and permissions on Laravel 5.8 App

Spatie role permission composer package provide way to create acl in Laravel 5.8. They provide how to assign role to user, how to assign permission to user and how to assign permission assign to roles. I will write step by step creating roles and permissions in Laravel 5.8 application.

Roles and Permissions through you can create several types of users with different role and permission, i mean some user have only see listing of items module, some user can also edit items modules, for delete and etc.

In this examples i created three modules as listed bellow:

  • User Management
  • Role Management
  • Product Management

After register user, you don't have any roles, so you can edit your details and assign admin role to you from User Management. After that you can create your own role with permission like role-list, role-create, role-edit, role-delete, product-list, product-create, product-edit, product-delete. You can check with assign new user and check that.

Step 1: Laravel 5.8 Installation

We are going from scratch so, If you haven't installed Laravel in your system then you can run bellow command and get fresh Laravel project.

<pre class="ql-syntax" spellcheck="false">composer create-project --prefer-dist laravel/laravel blog </pre>

Step 2: Install Composer Packages

Now we require to install Spatie package for ACL, that way we can use it's method. Also we will install form collection package. So Open your terminal and run bellow command.

<pre class="ql-syntax" spellcheck="false">composer require spatie/laravel-permission

composer require laravelcollective/html
</pre>

Now open config/app.php file and add service provider and aliase.

config/app.php

<pre class="ql-syntax" spellcheck="false">'providers' => [
....
Spatie\Permission\PermissionServiceProvider::class,
Collective\Html\HtmlServiceProvider::class,
],
'aliases' => [
....
'Form' => Collective\Html\FormFacade::class,
'Html' => Collective\Html\HtmlFacade::class,
],
</pre>

We can also custom changes on Spatie package, so if you also want to changes then you can fire bellow command and get config file in config/permission.php.

<pre class="ql-syntax" spellcheck="false">php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"
</pre>

Step 3: Create Migrations

In this step we have to create three migrations for as listed bellow tables:

1. users

2. products

3. roles

4. permissions

5. model_has_permissions

6. model_has_roles

7. role_has_permissions

So, if you install fresh project then you have already users table migration but if you don't have products table, so can create manually and other table can create using Spatie package command, so run bellow command and check migration file also.

<pre class="ql-syntax" spellcheck="false">php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"
php artisan make:migration create_products_table
</pre>

users table:

<pre class="ql-syntax" spellcheck="false"><?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email');
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::dropIfExists('users');
}

}
</pre>

products table:

<pre class="ql-syntax" spellcheck="false"><?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('detail');
$table->timestamps();
});
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::dropIfExists('products');
}

}
</pre>

Spatie tables:

<pre class="ql-syntax" spellcheck="false"><?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePermissionTables extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$tableNames = config('permission.table_names');

    Schema::create($tableNames['permissions'], function (Blueprint $table) {
        $table-&gt;increments('id');
        $table-&gt;string('name');
        $table-&gt;string('guard_name');
        $table-&gt;timestamps();
    });

    Schema::create($tableNames['roles'], function (Blueprint $table) {
        $table-&gt;increments('id');
        $table-&gt;string('name');
        $table-&gt;string('guard_name');
        $table-&gt;timestamps();
    });

    Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames) {
        $table-&gt;integer('permission_id')-&gt;unsigned();
        $table-&gt;morphs('model');

        $table-&gt;foreign('permission_id')
            -&gt;references('id')
            -&gt;on($tableNames['permissions'])
            -&gt;onDelete('cascade');

        $table-&gt;primary(['permission_id', 'model_id', 'model_type']);
    });

    Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames) {
        $table-&gt;integer('role_id')-&gt;unsigned();
        $table-&gt;morphs('model');

        $table-&gt;foreign('role_id')
            -&gt;references('id')
            -&gt;on($tableNames['roles'])
            -&gt;onDelete('cascade');

        $table-&gt;primary(['role_id', 'model_id', 'model_type']);
    });

    Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
        $table-&gt;integer('permission_id')-&gt;unsigned();
        $table-&gt;integer('role_id')-&gt;unsigned();

        $table-&gt;foreign('permission_id')
            -&gt;references('id')
            -&gt;on($tableNames['permissions'])
            -&gt;onDelete('cascade');

        $table-&gt;foreign('role_id')
            -&gt;references('id')
            -&gt;on($tableNames['roles'])
            -&gt;onDelete('cascade');

        $table-&gt;primary(['permission_id', 'role_id']);

        app('cache')-&gt;forget('spatie.permission.cache');
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    $tableNames = config('permission.table_names');

    Schema::drop($tableNames['role_has_permissions']);
    Schema::drop($tableNames['model_has_roles']);
    Schema::drop($tableNames['model_has_permissions']);
    Schema::drop($tableNames['roles']);
    Schema::drop($tableNames['permissions']);
}

}
</pre>

Now run migration:

<pre class="ql-syntax" spellcheck="false">php artisan migrate
</pre>

Step 4: Create Models

In this step we have to create model for User and Product table, so if you get fresh project then you have User Model have so just replace code and other you should create.

app/User.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
use Notifiable;
use HasRoles;

/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
protected $fillable = [
    'name', 'email', 'password',
];

/**
 * The attributes that should be hidden for arrays.
 *
 * @var array
 */
protected $hidden = [
    'password', 'remember_token',
];

/**
 * The attributes that should be cast to native types.
 *
 * @var array
 */
protected $casts = [
    'email_verified_at' =&gt; 'datetime',
];

}
</pre>

app/Product.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'detail'
];
}
</pre>

Step 5: Add Middleware

Spatie package provide it's in-built middleware that way we can use it simply and that is display as bellow:

role

permission

So, we have to add middleware in Kernel.php file this way :

app/Http/Kernel.php

<pre class="ql-syntax" spellcheck="false">....
protected $routeMiddleware = [
....
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
]
....
</pre>

Step 6: Create Authentication

In this step we require to create authentication of Laravel 5.8, so laravel provide artisan command to create authentication that way we don't require to create route and controller for login and registration. so run bellow command:

<pre class="ql-syntax" spellcheck="false">php artisan make:auth
</pre>

Step 7: Create Routes

We require to add number of route for users module, products module and roles module. In this this route i also use middleware with permission for roles and products route, so add route this way:

routes/web.php

<pre class="ql-syntax" spellcheck="false">Auth::routes();

Route::get('/home', '[email protected]')->name('home');

Route::group(['middleware' => ['auth']], function() {
Route::resource('roles','RoleController');
Route::resource('users','UserController');
Route::resource('products','ProductController');
});
</pre>

Step 8: Add Controllers

In this step we have add three controller for users module, products module and roles module so you can create three controller like as bellow:

app/Http/Controllers/UserController.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
use Spatie\Permission\Models\Role;
use DB;
use Hash;

class UserController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$data = User::orderBy('id','DESC')->paginate(5);
return view('users.index',compact('data'))
->with('i', ($request->input('page', 1) - 1) * 5);
}

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
public function create()
{
    $roles = Role::pluck('name','name')-&gt;all();
    return view('users.create',compact('roles'));
}

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    $this-&gt;validate($request, [
        'name' =&gt; 'required',
        'email' =&gt; 'required|email|unique:users,email',
        'password' =&gt; 'required|same:confirm-password',
        'roles' =&gt; 'required'
    ]);

    $input = $request-&gt;all();
    $input['password'] = Hash::make($input['password']);

    $user = User::create($input);
    $user-&gt;assignRole($request-&gt;input('roles'));

    return redirect()-&gt;route('users.index')
                    -&gt;with('success','User created successfully');
}

/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function show($id)
{
    $user = User::find($id);
    return view('users.show',compact('user'));
}

/**
 * Show the form for editing the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function edit($id)
{
    $user = User::find($id);
    $roles = Role::pluck('name','name')-&gt;all();
    $userRole = $user-&gt;roles-&gt;pluck('name','name')-&gt;all();

    return view('users.edit',compact('user','roles','userRole'));
}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function update(Request $request, $id)
{
    $this-&gt;validate($request, [
        'name' =&gt; 'required',
        'email' =&gt; 'required|email|unique:users,email,'.$id,
        'password' =&gt; 'same:confirm-password',
        'roles' =&gt; 'required'
    ]);

    $input = $request-&gt;all();
    if(!empty($input['password'])){ 
        $input['password'] = Hash::make($input['password']);
    }else{
        $input = array_except($input,array('password'));    
    }

    $user = User::find($id);
    $user-&gt;update($input);
    DB::table('model_has_roles')-&gt;where('model_id',$id)-&gt;delete();

    $user-&gt;assignRole($request-&gt;input('roles'));

    return redirect()-&gt;route('users.index')
                    -&gt;with('success','User updated successfully');
}

/**
 * Remove the specified resource from storage.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function destroy($id)
{
    User::find($id)-&gt;delete();
    return redirect()-&gt;route('users.index')
                    -&gt;with('success','User deleted successfully');
}

}
</pre>

app/Http/Controllers/ProductController.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App\Http\Controllers;

use App\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
/
function __construct()
{
$this->middleware('permission:product-list|product-create|product-edit|product-delete', ['only' => ['index','show']]);
$this->middleware('permission:product-create', ['only' => ['create','store']]);
$this->middleware('permission:product-edit', ['only' => ['edit','update']]);
$this->middleware('permission:product-delete', ['only' => ['destroy']]);
}
/
*
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$products = Product::latest()->paginate(5);
return view('products.index',compact('products'))
->with('i', (request()->input('page', 1) - 1) * 5);
}

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
public function create()
{
    return view('products.create');
}

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    request()-&gt;validate([
        'name' =&gt; 'required',
        'detail' =&gt; 'required',
    ]);

    Product::create($request-&gt;all());

    return redirect()-&gt;route('products.index')
                    -&gt;with('success','Product created successfully.');
}

/**
 * Display the specified resource.
 *
 * @param  \App\Product  $product
 * @return \Illuminate\Http\Response
 */
public function show(Product $product)
{
    return view('products.show',compact('product'));
}

/**
 * Show the form for editing the specified resource.
 *
 * @param  \App\Product  $product
 * @return \Illuminate\Http\Response
 */
public function edit(Product $product)
{
    return view('products.edit',compact('product'));
}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \App\Product  $product
 * @return \Illuminate\Http\Response
 */
public function update(Request $request, Product $product)
{
     request()-&gt;validate([
        'name' =&gt; 'required',
        'detail' =&gt; 'required',
    ]);

    $product-&gt;update($request-&gt;all());

    return redirect()-&gt;route('products.index')
                    -&gt;with('success','Product updated successfully');
}

/**
 * Remove the specified resource from storage.
 *
 * @param  \App\Product  $product
 * @return \Illuminate\Http\Response
 */
public function destroy(Product $product)
{
    $product-&gt;delete();

    return redirect()-&gt;route('products.index')
                    -&gt;with('success','Product deleted successfully');
}

}
</pre>

app/Http/Controllers/RoleController.php

<pre class="ql-syntax" spellcheck="false"><?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use DB;

class RoleController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
function __construct()
{
$this->middleware('permission:role-list|role-create|role-edit|role-delete', ['only' => ['index','store']]);
$this->middleware('permission:role-create', ['only' => ['create','store']]);
$this->middleware('permission:role-edit', ['only' => ['edit','update']]);
$this->middleware('permission:role-delete', ['only' => ['destroy']]);
}

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index(Request $request)
{
    $roles = Role::orderBy('id','DESC')-&gt;paginate(5);
    return view('roles.index',compact('roles'))
        -&gt;with('i', ($request-&gt;input('page', 1) - 1) * 5);
}

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
public function create()
{
    $permission = Permission::get();
    return view('roles.create',compact('permission'));
}

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    $this-&gt;validate($request, [
        'name' =&gt; 'required|unique:roles,name',
        'permission' =&gt; 'required',
    ]);

    $role = Role::create(['name' =&gt; $request-&gt;input('name')]);
    $role-&gt;syncPermissions($request-&gt;input('permission'));

    return redirect()-&gt;route('roles.index')
                    -&gt;with('success','Role created successfully');
}
/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function show($id)
{
    $role = Role::find($id);
    $rolePermissions = Permission::join("role_has_permissions","role_has_permissions.permission_id","=","permissions.id")
        -&gt;where("role_has_permissions.role_id",$id)
        -&gt;get();

    return view('roles.show',compact('role','rolePermissions'));
}

/**
 * Show the form for editing the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function edit($id)
{
    $role = Role::find($id);
    $permission = Permission::get();
    $rolePermissions = DB::table("role_has_permissions")-&gt;where("role_has_permissions.role_id",$id)
        -&gt;pluck('role_has_permissions.permission_id','role_has_permissions.permission_id')
        -&gt;all();

    return view('roles.edit',compact('role','permission','rolePermissions'));
}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function update(Request $request, $id)
{
    $this-&gt;validate($request, [
        'name' =&gt; 'required',
        'permission' =&gt; 'required',
    ]);

    $role = Role::find($id);
    $role-&gt;name = $request-&gt;input('name');
    $role-&gt;save();

    $role-&gt;syncPermissions($request-&gt;input('permission'));

    return redirect()-&gt;route('roles.index')
                    -&gt;with('success','Role updated successfully');
}
/**
 * Remove the specified resource from storage.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function destroy($id)
{
    DB::table("roles")-&gt;where('id',$id)-&gt;delete();
    return redirect()-&gt;route('roles.index')
                    -&gt;with('success','Role deleted successfully');
}

}
</pre>

Step 9: Add Blade Files

This is last step we have to add numbers view for layouts, users module, roles module, products modules and errors page, so create number of view like as bellow:

resources/views/layouts/app.blade.php

<pre class="ql-syntax" spellcheck="false"><html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel 5.8 User Roles and Permissions Tutorial') }}</title>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Raleway:300,400,600" rel="stylesheet" type="text/css">
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light navbar-laravel">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
Laravel 5.8 User Roles and Permissions - ItSolutionStuff.com
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>

            &lt;div class="collapse navbar-collapse" id="navbarSupportedContent"&gt;
                &lt;!-- Left Side Of Navbar --&gt;
                &lt;ul class="navbar-nav mr-auto"&gt;&lt;/ul&gt;

                &lt;!-- Right Side Of Navbar --&gt;
                &lt;ul class="navbar-nav ml-auto"&gt;
                    &lt;!-- Authentication Links --&gt;
                    @guest
                        &lt;li&gt;&lt;a class="nav-link" href="{{ route('login') }}"&gt;{{ __('Login') }}&lt;/a&gt;&lt;/li&gt;
                        &lt;li&gt;&lt;a class="nav-link" href="{{ route('register') }}"&gt;{{ __('Register') }}&lt;/a&gt;&lt;/li&gt;
                    @else
                        &lt;li&gt;&lt;a class="nav-link" href="{{ route('users.index') }}"&gt;Manage Users&lt;/a&gt;&lt;/li&gt;
                        &lt;li&gt;&lt;a class="nav-link" href="{{ route('roles.index') }}"&gt;Manage Role&lt;/a&gt;&lt;/li&gt;
                        &lt;li&gt;&lt;a class="nav-link" href="{{ route('products.index') }}"&gt;Manage Product&lt;/a&gt;&lt;/li&gt;
                        &lt;li class="nav-item dropdown"&gt;
                            &lt;a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre&gt;
                                {{ Auth::user()-&gt;name }} &lt;span class="caret"&gt;&lt;/span&gt;
                            &lt;/a&gt;

                            &lt;div class="dropdown-menu" aria-labelledby="navbarDropdown"&gt;
                                &lt;a class="dropdown-item" href="{{ route('logout') }}"
                                   onclick="event.preventDefault();
                                                 document.getElementById('logout-form').submit();"&gt;
                                    {{ __('Logout') }}
                                &lt;/a&gt;

                                &lt;form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;"&gt;
                                    @csrf
                                &lt;/form&gt;
                            &lt;/div&gt;
                        &lt;/li&gt;
                    @endguest
                &lt;/ul&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/nav&gt;

    &lt;main class="py-4"&gt;
        &lt;div class="container"&gt;
        @yield('content')
        &lt;/div&gt;
    &lt;/main&gt;
&lt;/div&gt;

</body>
</html>
</pre>

resources/views/users/index.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Users Management</h2>
</div>
<div class="pull-right">
<a class="btn btn-success" href="{{ route('users.create') }}"> Create New User</a>
</div>
</div>
</div>

@if ($message = Session::get('success'))
<div class="alert alert-success">
<p>{{ $message }}</p>
</div>
@endif

<table class="table table-bordered">
<tr>
<th>No</th>
<th>Name</th>
<th>Email</th>
<th>Roles</th>
<th width="280px">Action</th>
</tr>
@foreach ($data as $key => $user)
<tr>
<td>{{ ++$i }}</td>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>
@if(!empty($user->getRoleNames()))
@foreach($user->getRoleNames() as $v)
<label class="badge badge-success">{{ $v }}</label>
@endforeach
@endif
</td>
<td>
<a class="btn btn-info" href="{{ route('users.show',$user->id) }}">Show</a>
<a class="btn btn-primary" href="{{ route('users.edit',$user->id) }}">Edit</a>
{!! Form::open(['method' => 'DELETE','route' => ['users.destroy', $user->id],'style'=>'display:inline']) !!}
{!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
{!! Form::close() !!}
</td>
</tr>
@endforeach
</table>

{!! $data->render() !!}

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/users/create.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Create New User</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('users.index') }}"> Back</a>
</div>
</div>
</div>

@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

{!! Form::open(array('route' => 'users.store','method'=>'POST')) !!}
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Name:</strong>
{!! Form::text('name', null, array('placeholder' => 'Name','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Email:</strong>
{!! Form::text('email', null, array('placeholder' => 'Email','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Password:</strong>
{!! Form::password('password', array('placeholder' => 'Password','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Confirm Password:</strong>
{!! Form::password('confirm-password', array('placeholder' => 'Confirm Password','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Role:</strong>
{!! Form::select('roles[]', $roles,[], array('class' => 'form-control','multiple')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 text-center">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
{!! Form::close() !!}

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/users/edit.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Edit New User</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('users.index') }}"> Back</a>
</div>
</div>
</div>

@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

{!! Form::model($user, ['method' => 'PATCH','route' => ['users.update', $user->id]]) !!}
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Name:</strong>
{!! Form::text('name', null, array('placeholder' => 'Name','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Email:</strong>
{!! Form::text('email', null, array('placeholder' => 'Email','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Password:</strong>
{!! Form::password('password', array('placeholder' => 'Password','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Confirm Password:</strong>
{!! Form::password('confirm-password', array('placeholder' => 'Confirm Password','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Role:</strong>
{!! Form::select('roles[]', $roles,$userRole, array('class' => 'form-control','multiple')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 text-center">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
{!! Form::close() !!}

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/users/show.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2> Show User</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('users.index') }}"> Back</a>
</div>
</div>
</div>

<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Name:</strong>
{{ $user->name }}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Email:</strong>
{{ $user->email }}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Roles:</strong>
@if(!empty($user->getRoleNames()))
@foreach($user->getRoleNames() as $v)
<label class="badge badge-success">{{ $v }}</label>
@endforeach
@endif
</div>
</div>
</div>
@endsection
</pre>

resources/views/roles/index.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Role Management</h2>
</div>
<div class="pull-right">
@can('role-create')
<a class="btn btn-success" href="{{ route('roles.create') }}"> Create New Role</a>
@endcan
</div>
</div>
</div>

@if ($message = Session::get('success'))
<div class="alert alert-success">
<p>{{ $message }}</p>
</div>
@endif

<table class="table table-bordered">
<tr>
<th>No</th>
<th>Name</th>
<th width="280px">Action</th>
</tr>
@foreach ($roles as $key => $role)
<tr>
<td>{{ ++$i }}</td>
<td>{{ $role->name }}</td>
<td>
<a class="btn btn-info" href="{{ route('roles.show',$role->id) }}">Show</a>
@can('role-edit')
<a class="btn btn-primary" href="{{ route('roles.edit',$role->id) }}">Edit</a>
@endcan
@can('role-delete')
{!! Form::open(['method' => 'DELETE','route' => ['roles.destroy', $role->id],'style'=>'display:inline']) !!}
{!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
{!! Form::close() !!}
@endcan
</td>
</tr>
@endforeach
</table>

{!! $roles->render() !!}

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/roles/create.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Create New Role</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('roles.index') }}"> Back</a>
</div>
</div>
</div>

@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

{!! Form::open(array('route' => 'roles.store','method'=>'POST')) !!}
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Name:</strong>
{!! Form::text('name', null, array('placeholder' => 'Name','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Permission:</strong>
<br/>
@foreach($permission as $value)
<label>{{ Form::checkbox('permission[]', $value->id, false, array('class' => 'name')) }}
{{ $value->name }}</label>
<br/>
@endforeach
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 text-center">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
{!! Form::close() !!}

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/roles/edit.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Edit Role</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('roles.index') }}"> Back</a>
</div>
</div>
</div>

@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

{!! Form::model($role, ['method' => 'PATCH','route' => ['roles.update', $role->id]]) !!}
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Name:</strong>
{!! Form::text('name', null, array('placeholder' => 'Name','class' => 'form-control')) !!}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Permission:</strong>
<br/>
@foreach($permission as $value)
<label>{{ Form::checkbox('permission[]', $value->id, in_array($value->id, $rolePermissions) ? true : false, array('class' => 'name')) }}
{{ $value->name }}</label>
<br/>
@endforeach
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 text-center">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
{!! Form::close() !!}

@endsection
<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
</pre>

resources/views/roles/show.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2> Show Role</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('roles.index') }}"> Back</a>
</div>
</div>
</div>

<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Name:</strong>
{{ $role->name }}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Permissions:</strong>
@if(!empty($rolePermissions))
@foreach($rolePermissions as $v)
<label class="label label-success">{{ $v->name }},</label>
@endforeach
@endif
</div>
</div>
</div>
@endsection
</pre>

resources/views/products/index.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Products</h2>
</div>
<div class="pull-right">
@can('product-create')
<a class="btn btn-success" href="{{ route('products.create') }}"> Create New Product</a>
@endcan
</div>
</div>
</div>

@if ($message = Session::get('success'))
    &lt;div class="alert alert-success"&gt;
        &lt;p&gt;{{ $message }}&lt;/p&gt;
    &lt;/div&gt;
@endif

&lt;table class="table table-bordered"&gt;
    &lt;tr&gt;
        &lt;th&gt;No&lt;/th&gt;
        &lt;th&gt;Name&lt;/th&gt;
        &lt;th&gt;Details&lt;/th&gt;
        &lt;th width="280px"&gt;Action&lt;/th&gt;
    &lt;/tr&gt;
    @foreach ($products as $product)
    &lt;tr&gt;
        &lt;td&gt;{{ ++$i }}&lt;/td&gt;
        &lt;td&gt;{{ $product-&gt;name }}&lt;/td&gt;
        &lt;td&gt;{{ $product-&gt;detail }}&lt;/td&gt;
        &lt;td&gt;
            &lt;form action="{{ route('products.destroy',$product-&gt;id) }}" method="POST"&gt;
                &lt;a class="btn btn-info" href="{{ route('products.show',$product-&gt;id) }}"&gt;Show&lt;/a&gt;
                @can('product-edit')
                &lt;a class="btn btn-primary" href="{{ route('products.edit',$product-&gt;id) }}"&gt;Edit&lt;/a&gt;
                @endcan

                @csrf
                @method('DELETE')
                @can('product-delete')
                &lt;button type="submit" class="btn btn-danger"&gt;Delete&lt;/button&gt;
                @endcan
            &lt;/form&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    @endforeach
&lt;/table&gt;

{!! $products-&gt;links() !!}

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/products/create.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Add New Product</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('products.index') }}"> Back</a>
</div>
</div>
</div>

@if ($errors-&gt;any())
    &lt;div class="alert alert-danger"&gt;
        &lt;strong&gt;Whoops!&lt;/strong&gt; There were some problems with your input.&lt;br&gt;&lt;br&gt;
        &lt;ul&gt;
            @foreach ($errors-&gt;all() as $error)
                &lt;li&gt;{{ $error }}&lt;/li&gt;
            @endforeach
        &lt;/ul&gt;
    &lt;/div&gt;
@endif

&lt;form action="{{ route('products.store') }}" method="POST"&gt;
	@csrf

     &lt;div class="row"&gt;
	    &lt;div class="col-xs-12 col-sm-12 col-md-12"&gt;
	        &lt;div class="form-group"&gt;
	            &lt;strong&gt;Name:&lt;/strong&gt;
	            &lt;input type="text" name="name" class="form-control" placeholder="Name"&gt;
	        &lt;/div&gt;
	    &lt;/div&gt;
	    &lt;div class="col-xs-12 col-sm-12 col-md-12"&gt;
	        &lt;div class="form-group"&gt;
	            &lt;strong&gt;Detail:&lt;/strong&gt;
	            &lt;textarea class="form-control" style="height:150px" name="detail" placeholder="Detail"&gt;&lt;/textarea&gt;
	        &lt;/div&gt;
	    &lt;/div&gt;
	    &lt;div class="col-xs-12 col-sm-12 col-md-12 text-center"&gt;
	            &lt;button type="submit" class="btn btn-primary"&gt;Submit&lt;/button&gt;
	    &lt;/div&gt;
	&lt;/div&gt;

&lt;/form&gt;

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/products/edit.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Edit Product</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('products.index') }}"> Back</a>
</div>
</div>
</div>

@if ($errors-&gt;any())
    &lt;div class="alert alert-danger"&gt;
        &lt;strong&gt;Whoops!&lt;/strong&gt; There were some problems with your input.&lt;br&gt;&lt;br&gt;
        &lt;ul&gt;
            @foreach ($errors-&gt;all() as $error)
                &lt;li&gt;{{ $error }}&lt;/li&gt;
            @endforeach
        &lt;/ul&gt;
    &lt;/div&gt;
@endif

&lt;form action="{{ route('products.update',$product-&gt;id) }}" method="POST"&gt;
	@csrf
    @method('PUT')

     &lt;div class="row"&gt;
	    &lt;div class="col-xs-12 col-sm-12 col-md-12"&gt;
	        &lt;div class="form-group"&gt;
	            &lt;strong&gt;Name:&lt;/strong&gt;
	            &lt;input type="text" name="name" value="{{ $product-&gt;name }}" class="form-control" placeholder="Name"&gt;
	        &lt;/div&gt;
	    &lt;/div&gt;
	    &lt;div class="col-xs-12 col-sm-12 col-md-12"&gt;
	        &lt;div class="form-group"&gt;
	            &lt;strong&gt;Detail:&lt;/strong&gt;
	            &lt;textarea class="form-control" style="height:150px" name="detail" placeholder="Detail"&gt;{{ $product-&gt;detail }}&lt;/textarea&gt;
	        &lt;/div&gt;
	    &lt;/div&gt;
	    &lt;div class="col-xs-12 col-sm-12 col-md-12 text-center"&gt;
	      &lt;button type="submit" class="btn btn-primary"&gt;Submit&lt;/button&gt;
	    &lt;/div&gt;
	&lt;/div&gt;

&lt;/form&gt;

<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
@endsection
</pre>

resources/views/products/show.blade.php

<pre class="ql-syntax" spellcheck="false">@extends('layouts.app')

@section('content')
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2> Show Product</h2>
</div>
<div class="pull-right">
<a class="btn btn-primary" href="{{ route('products.index') }}"> Back</a>
</div>
</div>
</div>

&lt;div class="row"&gt;
    &lt;div class="col-xs-12 col-sm-12 col-md-12"&gt;
        &lt;div class="form-group"&gt;
            &lt;strong&gt;Name:&lt;/strong&gt;
            {{ $product-&gt;name }}
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="col-xs-12 col-sm-12 col-md-12"&gt;
        &lt;div class="form-group"&gt;
            &lt;strong&gt;Details:&lt;/strong&gt;
            {{ $product-&gt;detail }}
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

@endsection
<p class="text-center text-primary"><small>Tutorial by ItSolutionStuff.com</small></p>
</pre>

Step 10: Handle Exertion Error

Now, in this step we will handle exertion. if you don't have a permission and try to access that page using browser url then you can give message as like bellow:

add/Exceptions/Handler.php

<pre class="ql-syntax" spellcheck="false">......
public function render($request, Exception $exception)
{
if ($exception instanceof \Spatie\Permission\Exceptions\UnauthorizedException) {
return response()->json(['User have not permission for this page access.']);
}

return parent::render($request, $exception);

}
....
</pre>

Step 11: Create Seeder For Permissions and AdminUser

In this step we will create seeder for permissions, Right now we have fixed permission so we create using seeder as listed bellow, but if you can add more permission as you want:

1.role-list

2.role-create

3.role-edit

4.role-delete

5.product-list

6.product-create

7.product-edit

8.product-delete

So, first create seeder using bellow command:

<pre class="ql-syntax" spellcheck="false">php artisan make:seeder PermissionTableSeeder
</pre>

And put bellow code in PermissionTableSeeder seeder this way:

database/seeds/PermissionTableSeeder.php

<pre class="ql-syntax" spellcheck="false"><?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;

class PermissionTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$permissions = [
'role-list',
'role-create',
'role-edit',
'role-delete',
'product-list',
'product-create',
'product-edit',
'product-delete'
];

    foreach ($permissions as $permission) {
         Permission::create(['name' =&gt; $permission]);
    }
}

}
</pre>

After this we have to run bellow command for run PermissionTableSeeder seeder:

<pre class="ql-syntax" spellcheck="false">php artisan db:seed --class=PermissionTableSeeder
</pre>

Now let's create new seeder for creating admin user.

<pre class="ql-syntax" spellcheck="false">php artisan make:seeder CreateAdminUserSeeder
</pre>

database/seeds/PermissionTableSeeder.php

<pre class="ql-syntax" spellcheck="false"><?php

use Illuminate\Database\Seeder;
use App\User;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class CreateAdminUserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$user = User::create([
'name' => 'Hardik Savani',
'email' => '[email protected]',
'password' => bcrypt('123456')
]);

    $role = Role::create(['name' =&gt; 'Admin']);

    $permissions = Permission::pluck('id','id')-&gt;all();

    $role-&gt;syncPermissions($permissions);

    $user-&gt;assignRole([$role-&gt;id]);
}

}
php artisan db:seed --class=CreateAdminUserSeeder
</pre>

Now we are ready to to run full example of ACL. so let's run our example so run bellow command for quick run:

<pre class="ql-syntax" spellcheck="false">php artisan serve
</pre>

Access By

<pre class="ql-syntax" spellcheck="false">http://localhost:8000/
</pre>

Now you can login with following credential:

<pre class="ql-syntax" spellcheck="false">Email: [email protected]
Password: 123456
</pre>

You can see bellow screenshots:

You can download code from GitHub

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow me on Facebook | Twitter

Learn More about

PHP with Laravel for beginners - Become a Master in Laravel

Projects in Laravel: Learn Laravel Building 10 Projects

Laravel for RESTful: Build Your RESTful API with Laravel

Fullstack Web Development With Laravel and Vue.js

Laravel 5.8 Ajax CRUD tutorial using Datatable JS

Laravel 5.8 Tutorial from Scratch for Beginners

Build RESTful API In Laravel 5.8 Example

Login with Google in Laravel 5.8 App using Socialite Package

Laravel PHP Framework Tutorial - Full Course for Beginners (2019)