In this article, I will show you how to implement CRUD (Create, Read, Update, Delete) functionality for a database entity. We will start by creating the tables in the database, after that we will define the entity in the java code. We will use spring-data-jpa to implement JPA repositories and we will define a RestController with Restful services for the entity. After that we will implement user interface for the REST API, with the help of the AngularJS framework. The whole project is available in the following github repository.
Implementation of the back-end
We will start the implementation of the back-end by preparing the database. After that we will create a maven project with Spring Tool Suite and we will implement the rest of the back-end functionality.
Create the database tables
Let’s create the following tables: Department and Employee with relation many to one between them. Many employees can be in the same department but one employee has only one department. For the example I will use PostgreSQL instead of the in memory database, because I want to show you how to configure the database in the Spring ecosystem. Below are listed the queries that create the two tables:
CREATE TABLE department ( id serial, name character varying(255) NOT NULL, description character varying(255) NOT NULL, CONSTRAINT department_pk PRIMARY KEY (id) ) CREATE TABLE employee ( id serial NOT NULL, name character varying(255), salary integer NOT NULL, department_id integer, CONSTRAINT employee_pkey PRIMARY KEY (id), CONSTRAINT employee_department_fkey FOREIGN KEY (department_id) REFERENCES department (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT department_name_unique UNIQUE (department_id, name) )
Setup the project with maven
Ok we are ready with the database setup, now let’s create a maven project in the STS(Spring Tool Suite) IDE.
1. Download and install Spring Tool Suite.
2. Once you run it, go to File -> New -> Maven Project
3. Check “Create a simple project (skip archetype selection)” and click Next
4. Populate Group Id with package name like: eu.dreamix.crud, and populate Artifact Id with just the last of the package name – crud. The part in the Group Id with name “crud” is the name of the application. This link here describes the naming convention for Group Id and Artifact Id: https://maven.apache.org/guides/mini/guide-naming-conventions.html
5. Change the packaging to war and click Finish.
6. The first thing that we can notice is that we have an error in our pom file. This is because we chose war packaging but there is no web.xml file. We don’t need web.xml because we will use Spring Boot, so we simply have to add the necessary configuration and dependencies in the pom.xml file.
7. Change the pom file to include:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
8. Call maven update by clicking with the right button on the project -> Maven -> Update Project (or simply press alt + F5). The error should disappear now.
9. The last step is to create a class with main method that will run our application. Create a package eu.dreamix.crud. Add a new class with a name CrudApp, check the checkbox to create main method. Modify the class according to the code below:
package eu.dreamix.crud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class CrudApp { public static void main(String[] args) { SpringApplication.run(CrudApp.class, args); } }
10. Now we have fully setup spring boot application. If we run the application it will start embedded tomcat server and we will be able to access it at localhost:8080. However we don’t have any actions implemented yet, so let’s create a simple rest controller to show a greeting message. I like to put the rest controllers in a sub package, so create a sub package eu.dreamix.crud.rest and create a class GreetingController:
package eu.dreamix.crud.rest; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class GreetingController { @RequestMapping("/") public String index() { return "Greetings!"; } }
11. If we run the application and access https://localhost:8080/ we will see our “Greetings!” message. We are ready with the initial setup of the application.
Implement JPA Entities
We have our application up and running, we can now create the JPA entities reflecting the tables that we created in the database.
1. The first step is to add the spring-data-jpa dependency in our pom file. Add the following dependency under the dependencies tag:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
2. Now we have all the annotations that will allow us to define the entity. Firstly, create another package eu.dreamix.crud.domain. In this package we will put our entities which define the domain of the application. Create a class Department as follows:
package eu.dreamix.crud.domain; // Imports ... @Entity public class Department { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @NotNull private String name; @NotNull private String description; public Department() { } public Department(String name, String description) { super(); this.name = name; this.description = description; } // Setters and Getters }
As you can see the class is annotated with @Entity, which marks it as database entity. The field id of type Integer is marked with annotation @Id which is used to specify the primary key for the entity. The annotation @GeneratedValue marks the field to use auto increment and GeneretionType.IDENTITY defines the auto increment strategy. The other two fields are annotated with @NotNull which is very descriptive. It forces the fields to not accept null values.
3. Let’s create the Employee entity. It is a bit more complex, because we will implement many-to-one relationship with the department entity. Create a class Employee as follows:
package eu.dreamix.crud.domain; // Imports ... @Entity @Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "department_id", "name" }) }) public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; @ManyToOne @JoinColumn(name = "department_id", referencedColumnName = "id") private Department department; private Integer salary; public Employee() { } public Employee(String name, Department department, int salary) { super(); this.name = name; this.department = department; this.salary = salary; } // Setters and Getters }
Here we use @ManyToOne annotation to implement a many-to-one relationship between Employee and Department. With @JoinColumn we point the field that relates to the other table. In “name” we write the name of the column in the employee table and in “referencedColumnName” we write the name of the column in the department table. With @Table and @UniqueConstraint we implement a composite unique constraint for the fields department_id and name. This creates a restriction to prevent inserting same Employee in different Department.
4. We will continue by configuring the database connection. In order to connect the database with our project, we must create a configuration file that Spring can find. Spring can find the configuration from a lot of places but I like to put it in the resources folder. In this Spring Reference of Spring Boot, we can see all the places where we can put our confguration: https://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-external-config-application-property-files
So create a file in the the folder src/main/resources/config with the name application.yml, like it is shown in the screenshot.
The content of the file is as follows:
spring: datasource: url: jdbc:postgresql://localhost:5432/crud_example username: postgres password: pass driver-class-name: org.postgresql.Driver
We can also create a .properties file, but I find the yml format more pretty. So as you can see we configure the jdbc url, username, password and driver class. As you can notice we are using a postgres driver but we don’t have it yet in our project. In order to add the driver to our application we must add another dependency in the pom file. Add the following between the <dependencies> tag.
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency>
Note that if you are using other database, you need to add the driver for the particular database that you use. For example if you use MySQL, you must configure the MySQL driver.
Here I also want to mention that you can configure the application to use the so called code-first approach. Code-first means that we first design our entities as java classes and then the application creates the tables by itself. In order to configure this behavior in our application we need to add the following configuration under spring tag:
spring: datasource: url: jdbc:postgresql://localhost:5432/crud_example username: postgres password: pass driver-class-name: org.postgresql.Driver jpa: properties: hibernate.hbm2ddl.auto: update
This key: hibernate.hbm2ddl.auto is from the hibernate library that spring-data-jpa uses. There are other values that can be configured. The update will only update or create the tables if they don’t exist.
One last thing about the configuration, we can change the type of the DataSource. Spring has several default choices if they are available in the classpath. You can read more about production DataSources in the Spring Boot Reference here: https://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-connect-to-production-database
That was all about the entities, there are a lot more useful annotations, however they are not included in this article. For example we often need to exclude some fields when we represent the objects in JSON and there is an annotation that can help us with this.
Implement JPA Repository
Now that we have all entities implemented, we can use them to map data from the tables as java objects. This is implemented with repositories. We will start by creating a simple employee repository.
1. Create a new package eu.dreamix.crud.repository. We will put all our repositories in this package.
2. Create an interface EmployeeRepository as follows:
package eu.dreamix.crud.repository; import org.springframework.data.jpa.repository.JpaRepository; import eu.dreamix.crud.domain.Employee; public interface EmployeeRepository extends JpaRepository<Employee, Integer> { Employee findByName(String name); }
That is all we need to create, update, read and delete records from the database programmatically. To be honest I was really surprised when I found out that I don’t need to implement any logic at all in order to communicate with the database. Spring is so smart that only from this code, it knows how to implement the interface and offer us the functionality. Here it is probably good to mention that we can add other methods that Spring will implement for us out of the box. For example we can add a method,  findByName(String name) and that will be enough to get the record with the given name. You can read more about this in Spring Boot Reference here: https://docs.spring.io/spring-boot/docs/1.5.2.RELEASE/reference/htmlsingle/#boot-features-spring-data-jpa-repositories
3. Let’s create one more repository for the Department entity. Create an interface DepartmentRepository as follows:
package eu.dreamix.crud.repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import eu.dreamix.crud.domain.Department; public interface DepartmentRepository extends JpaRepository<Department, Integer> { List<Department> findAllByDescription(String description); }
You can notice here that we implemented one query method that makes searches by description.
That was all about the repositories. Pretty easy right?
Implement Services
This part is not really necessary but I like to create services in order to separate the business logic. For our simple example we don’t have a lot of business logic, however in a real project we will probably need the service layer. This is pretty standard architecture of a web application. We have a persistence layer, a business/service layer and presentation layer. Let’s create a simple service that will make all interactions with the repositories.
1. Create a new package eu.dreamix.crud.service. We will put all services in this package.
2. Create a class EmployeeService as follows:
package eu.dreamix.crud.service; // Imports ... @Service public class EmployeeService { private EmployeeRepository employeeRepository; @Autowired public EmployeeService(EmployeeRepository employeeRepository) { this.employeeRepository = employeeRepository; } public Employee save(Employee employee) { if (employee.getId() != null && employeeRepository.exists(employee.getId())) { throw new EntityExistsException("There is already existing entity with such ID in the database."); } return employeeRepository.save(employee); } public Employee update(Employee employee) { if (employee.getId() != null && !employeeRepository.exists(employee.getId())) { throw new EntityNotFoundException("There is no entity with such ID in the database."); } return employeeRepository.save(employee); } public List<Employee> findAll() { return employeeRepository.findAll(); } public Employee findOne(Integer id) { return employeeRepository.findOne(id); } public void delete(Integer id) { employeeRepository.delete(id); } }
In this service we have all methods that we need to create, update, delete and read records. We marked the class with @Service annotation, in order to inform spring that this is a service. We use @Autowired annotation in the constructor to autowire the EmployeeRepository. Note that this @Autowired annotation is not necessary if we have only one constructor as of spring 4.3 version, however I put it anyway because it is more descriptive that we use constructor injection. The implementation is very simple, we use the methods provided by the repository to manipulate the records. The Repository doesn’t offer an update method. The method save will update a record if it already exists and will create a new one if there is no such record yet. That is why for the save and update methods we first check if there is such an entry in the database. We throw appropriate exceptions for the situations that we are interested in. Later on we will handle them in the REST controllers.
3. Create a class DepartmentService as follows:
package eu.dreamix.crud.service; // Imports ... @Service public class DepartmentService { private DepartmentRepository departmentRepository; @Autowired public DepartmentService(DepartmentRepository departmentRepository) { this.departmentRepository = departmentRepository; } public Department save(Department department) { if (department.getId() != null && departmentRepository.exists(department.getId())) { throw new EntityExistsException("There is already existing entity with such ID in the database."); } return departmentRepository.save(department); } public Department update(Department department) { if (department.getId() != null && !departmentRepository.exists(department.getId())) { throw new EntityNotFoundException("There is no entity with such ID in the database."); } return departmentRepository.save(department); } public List<Department> findAll() { return departmentRepository.findAll(); } public Department findOne(Integer id) { return departmentRepository.findOne(id); } public void delete(Integer id) { departmentRepository.delete(id); } }
We are now ready with the services. The department service is a lot like the employee service, so I am not going to describe the implementation.
Implement REST Controller
Let’s implement now the rest controllers that our front-end will use to manipulate the entities. We will start with the employee resource.
1. Create a new class under eu.dreamix.crud.rest called EmployeeResource with the following content:
package eu.dreamix.crud.rest; // Imports ... @RestController @RequestMapping("/api") public class EmployeeResource { private EmployeeService employeeService; public EmployeeResource(EmployeeService employeeService) { this.employeeService = employeeService; } @RequestMapping(value = "employee", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List<Employee> getAllEmployees() { return employeeService.findAll(); } @RequestMapping(value = "employee", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Employee> createEmployee(@RequestBody Employee employee) throws URISyntaxException { try { Employee result = employeeService.save(employee); return ResponseEntity.created(new URI("/api/employee/" + result.getId())).body(result); } catch (EntityExistsException e) { return new ResponseEntity<Employee>(HttpStatus.CONFLICT); } } @RequestMapping(value = "employee", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Employee> updateEmployee(@RequestBody Employee employee) throws URISyntaxException { if (employee.getId() == null) { return new ResponseEntity<Employee>(HttpStatus.NOT_FOUND); } try { Employee result = employeeService.update(employee); return ResponseEntity.created(new URI("/api/employee/" + result.getId())).body(result); } catch (EntityNotFoundException e) { return new ResponseEntity<Employee>(HttpStatus.NOT_FOUND); } } @RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Void> deleteEmployee(@PathVariable Integer id) { employeeService.delete(id); return ResponseEntity.ok().build(); } }
In order to define the class as a rest controller we use the @RestController annotation. With @RequestMapping(“/api”) we define a root path that all methods will go under. We use the same annotation @RequestMapping when we define the methods as well, but there we define specific path only applied for the method. With the same annotation we define the method type ( GET, POST, PUT, DELETE etc.) and the returned media type. With @RequestBody we mark that a method parameter should be expected in the body of the request. With @PathVariable we mark that a method parameter should be retrieved from the requested path. Check the path for the delete method, there we define a variable {id} in the path itself. There is one more kind of parameters called query parameters, they are defined with @RequestParam and they are retrieved again from the url path but after the question mark (for example /api/employee?name=John). The rest of the implementation is self descriptive, we call the methods from the EmployeeService and we handle the exceptions. Note that for the update method I make one validation if the employee id is null. This logic should be implemented in the service as well. Basically when I develop rest services I try to minimize the code in the rest controller and put everything in the services. Here I will mention that we can even get rid of the code that handles the exceptions with the aspect oriented concepts implemented in spring. We can define a behavior, in event of an exception, for all rest controllers. Then we won’t need to implement try and catch for every method in every rest controller. The annotation used for this is @ControllerAdvice but it is not part of this article.
2. Create a new class under eu.dreamix.crud.rest called DepartmentResource with the following content:
package eu.dreamix.crud.rest; // Imports ... @RestController @RequestMapping("/api") public class DepartmentResource { private DepartmentService departmentService; public DepartmentResource(DepartmentService departmentService) { this.departmentService = departmentService; } @RequestMapping(value = "department", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List<Department> getAllDepartments() { return departmentService.findAll(); } @RequestMapping(value = "department", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Department> createDepartment(@RequestBody Department department) throws URISyntaxException { Department result = departmentService.save(department); return ResponseEntity.created(new URI("/api/department/" + result.getId())).body(result); } @RequestMapping(value = "department", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Department> updateDepartment(@RequestBody Department department) throws URISyntaxException { if (department.getId() == null) { return new ResponseEntity<Department>(HttpStatus.NOT_FOUND); } try { Department result = departmentService.update(department); return ResponseEntity.created(new URI("/api/department/" + result.getId())).body(result); } catch (EntityNotFoundException e) { return new ResponseEntity<Department>(HttpStatus.NOT_FOUND); } } @RequestMapping(value = "/department/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Void> deleteDepartment(@PathVariable Integer id) { departmentService.delete(id); return ResponseEntity.ok().build(); } }
Again I won’t go into details about the implementation for DepartmentResource because it is very much similar to the EmployeeResource implementation.
With this we are finished with the the back-end and we can start implementing a client for our application.
Implementation of the front-end
The front-end will be implemented with AngularJS. We communicate with the back-end by making requests only for data. As comparison with other technologies, with JSF we prepare the UI in the back-end as well and we send the whole HTML to the client. However with the technology stack of this article we send the HTML only once and through JavaScript, we make asynchronous HTTP requests to retrieve data from the back-end. Then with the help of the JavaScript framework AngularJS we update the HTML accordingly.
Setup the AngularJS
Firstly we need to add new index.html file under /src/main/webapp and delete the GreetingController. By doing this we will make the spring boot load our index.html page at root, instead of the greeting message.
In order to use the AngularJS we simply have to add the dependency in our HTML. Since we will be making Http requests, we need to add another javascript to our project – angular-resource.js. I also include bootstrap in order to style and structure the UI, however this is not required. I use google CDN to add the javascripts in my project, but for a real project it is better to download the minified versions of the files and include them in the project. Those are the files that I include in the <head> of the html.
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular-resource.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
The jQuery is added because it is required by bootstrap. In order to create angular application I created another javascript under /webapp/app/ folder called app.js with the following content:
var app = angular.module("crudApp", ['ngResource']);
Note that every new javascript file that we create must be added in index.html as well. This code defines a new angular application, it is just one line but I like to keep the things separated. The ngResource is a module that our application uses. It comes from the file angular-resource.js. There is one last step, we must put ng-app attribute in our html <body> like this:
<body ng-app="crudApp">
By doing this we define the scope of our application to be over the whole body.
Creating Angular Service to access the REST API
All the logic can be implemented in an angular controller, however it is a good idea to separate the logic that is not responsible for updating of the HTML in an angular service. We will put the logic that makes requests to the back-end in two services.
1. Create a file under webapp/app/ called employee.service.js and add it to the index.html. Below is the content of the file:
angular.module('crudApp').factory('Employee', Employee); Employee.$inject = [ '$resource' ]; function Employee($resource) { var resourceUrl = 'api/employee/:id'; return $resource(resourceUrl, {}, { 'update' : { method : 'PUT' } }); }
This code will create a service Employee. You probably noticed that we called again angular.module(), however this time we didn’t pass an array in the function. If we don’t pass an array of dependencies in the angular.module(), the function will return an already existing module with this name instead of creating new one. With the factory method we define a service, and with $Inject we include dependencies that we will use in our service. Here we are using the $resource factory which allows us to make REST calls to the back-end. It is a wrapper around $http and offers us more convenient way to implement our logic. You can read more about $resource in the angular documentation here: https://docs.angularjs.org/api/ngResource/service/$resource
2. Create a file under webapp/app/ called department.service.js with the following content:
angular.module(‘crudApp’).factory(‘Department’, Department);
Department.$inject = [ '$resource' ]; function Department($resource) { var resourceUrl = 'api/department/:id'; return $resource(resourceUrl, {}, { 'update' : { method : 'PUT' } }); }
This code will create a Department service. It is similar to the employee service.
Creating a controller
The logic in the controller should be only concerned with the flow of user actions and the displayed content. For the example I created only one controller called, GeneralController. Create a file in the folder webapp/app/general.controller.js and include the file in index html. Below is the content of the file:
angular.module("crudApp").controller("GeneralController", GeneralController); GeneralController.inject = [ '$scope', 'Employee', 'Department' ]; function GeneralController($scope, Employee, Department) { $scope.departments = Department.query(); $scope.employees = Employee.query(); $scope.employee = {}; $scope.department = {}; $scope.saveEmployee = function() { if ($scope.employee.id !== undefined) { Employee.update($scope.employee, function() { $scope.employees = Employee.query(); $scope.employee = {}; }); } else { Employee.save($scope.employee, function() { $scope.employees = Employee.query(); $scope.employee = {}; }); } } $scope.updateEmployeeInit = function(employee) { $scope.employee = employee; } $scope.deleteEmployee = function(employee) { employee.$delete({id: employee.id}, function() { $scope.employees = Employee.query(); }); } $scope.saveDepartment = function() { if ($scope.department.id !== undefined) { Department.update($scope.department, function() { $scope.departments = Department.query(); $scope.department = {}; }); } else { Department.save($scope.department, function() { $scope.departments = Department.query(); $scope.department = {}; }); } } $scope.deleteDepartment = function(department) { department.$delete({id: department.id}, function() { $scope.departments = Department.query(); }); } $scope.updateDepartmentInit = function(department) { $scope.department = department; } }
With the controller() function we create an angular controller. In order to use our controller we must define it in the HTML as well. I want this controller to operate over the whole html so I added it in the body tag as follows:
<body ng-app="crudApp" ng-controller="GeneralController">
You will probably notice that we use a lot $scope in the code. The $scope is used to attach variables and functions that we can use in the HTML. Through the scope we implement two way binding, meaning that if some variable gets updated in the controller, it will be reflected in the UI and if some value in the HTML changes it will be reflected in the controller as well. I won’t go over every method in the controller because they are pretty straight forward. Only the updating of a record consist of two actions. The first one is when we initialize the updating, this will put the content of the record that we want to update in the input fields and when we click submit it will save them in the database.
Creating the user interface
For the user interface as I mentioned I use the bootstrap library. The UI is very simple and it only demonstrates the functionality. It is implemented in the index.html file. Here is a screenshot of how it looks:
Creating UI for Departments
Below is the html code to create, read, update and delete department entities. This code is located right under the body opening tag.
<div class="panel panel-default"> <div class="panel-heading">Departments</div> <div class="panel-body"> <div class="col-md-4"> <form ng-submit="saveDepartment()"> <div class="form-group"> <label for="departmentName">Department Name</label> <input type="text" ng-model="department.name" class="form-control" id="departmentName" placeholder="Department Name"> </div> <div class="form-group"> <label for="departmentDescription">Department Description</label> <input type="text" ng-model="department.description" class="form-control" id="departmentDescription" placeholder="Description"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> </div> <div class="table-responsive col-md-6"> <table class="table table-striped"> <tr><th>Name</th><th>Description</th><th></th></tr> <tr ng-repeat="department in departments"> <td>{{department.name}}</td> <td>{{department.description}}</td> <td><button type="button" class="btn btn-default" ng-click="updateDepartmentInit(department)"><span class="glyphicon glyphicon-edit" aria-hidden="true"></span></button> <button type="button" class="btn btn-default" ng-click="deleteDepartment(department)"> <span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span></button> </td></tr> </table> </div> </div> </div>
In this implementation we use several angular directives to attach the HTML with the javascript. One of them is ng-submit which takes function that is executed when the form is submitted. With ng-model we bind a javascript variable to html input field or select field. One interesting directive is ng-repeat. It is like a foreach loop and it repeats the html content defined inside it for every record. The ng-click again takes a function that is executed on every click of the component. We can use the curly brackets to write angular expressions, which are javascript code inside the HTML. For example {{department.name}} will display the field name of the object department.
Creating UI for Employees
The UI for Employees is very similar to the departments UI. Below is the code:
<div class="panel panel-default"> <div class="panel-heading">Employees</div> <div class="panel-body"> <form class="col-md-4" ng-submit="saveEmployee()"> <div class="form-group"> <label for="employeeName">Employee Name</label> <input type="text" ng-model="employee.name" class="form-control" id="employeeName" placeholder="Employee Name"> </div> <div class="form-group"> <label for="employeeSalary">Salary</label> <input type="text" ng-model="employee.salary" class="form-control" id="employeeSalary" placeholder="Salary"> </div> <div class="form-group"> <label for="employeeDepartment">Department</label> <select class="form-control" id="field_organization" name="organization" ng-model="employee.department" ng-options="department as department.name for department in departments track by department.id"> </select> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <div class="table-responsive col-md-6"> <table class="table table-striped"> <tr> <th>Name</th> <th>Salary</th> <th>Department</th> <th></th> </tr> <tr ng-repeat="employee in employees"> <td>{{employee.name}}</td> <td>{{employee.salary}}</td> <td>{{employee.department.name}}</td> <td> <button type="button" class="btn btn-default" ng-click="updateEmployeeInit(employee)"> <span class="glyphicon glyphicon-edit" aria-hidden="true"></span> </button> <button type="button" class="btn btn-default" ng-click="deleteEmployee(employee)"> <span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span></button> </td> </tr> </table> </div> </div> </div>
There is only one different part here, the select tag. Again with the help of angular, we can bind variable in which we want to save the selected value with ng-model and we can bind another variable from where the list of values are taken.
That was everything about the UI. I hope the article was helpful. Leave a comment if you know a better way to implement any part of the article or if you use other technologies to implement such functionalities.