Displaying Database table data on Html table tag

Connel Asikong
15 min readJul 15, 2017

In this… don’t want to call it a tutorial, let me just say a heads-up-ish, we’ll build a simple webapp using golang and MySql and a new-gaining grounds CSS framework known as Tachyons. To learn how to use some of the basic css visit Their docs. This small project is without any Golang microframework. I name the app CRUD not Grodd in flash! It’ll have the following features:

  1. Create users
  2. Read users
  3. Update users
  4. Delete users
  5. Just a lil design no javascript for now
  6. coffee

Are you ready? Oh damn! you’re too excited you making your computer nervous. Be calm.

Now where were we? Okay are you ready? Oh! That’s the first gopher in space. Her name is … we’ll be back shortly.

Prerequisites

In this tutorial i assume you are already familiar with golang, mysql, html/css etc if not download and install the necessary things needed for the job.

At least know HTML and CSS with a little knowledge of golang templating and how to use Mysql. If not, visit the links I posted above to learn more.

This tutorial uses the idiomatic way Go setup projects.

Database Setup

Go doesn’t provide official database drivers, unlike other languages . It does have some database driver interface standards for you to develop database drivers with. The advantage is that if your code is developed according to these interface standards, you will not need to change any code if your database changes.

MySql Drivers

There are a couple of drivers that support MySQL in Go.

I’ll be going with the one written in pure go.

We’ll create the MySql database. Make sure you have MySql running and you have logged in.

create database:

CREATE SCHEMA `Crud_db` ;

then create table:

CREATE TABLE `GoStaffManager`.`Users` (

`id` INT(11) NOT NULL AUTO_INCREMENT,

`username` VARCHAR(45) NULL DEFAULT NULL,

`password` VARCHAR(200) NULL DEFAULT NULL,

`created_at` VARCHAR(45) NULL DEFAULT NULL,

`updated_at` VARCHAR(45) NULL DEFAULT NULL,

`is_admin` INT(11) NULL DEFAULT NULL,

PRIMARY KEY (`id`));

You have gotten your database all set up. look at that smile 😊😊

Before we continue, you could create a project in your GOPATH dir, I call mine crud.

Templates

Now setup your front-end. How do you want it to look like.

Now in crud folder create template folder, so your directory should look like this: crud/templates/. Then inside templates create a dir for admin.

Now let’s start with index page, create a index.html page inside template

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CRUD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/assets/css/tachyons.css">
</head>
<body>
<main class="flex flex-column min-vh-100"><!-- use flex to separate the layouts into diff sections. -->
<header class="w-100">
<div class="w-100 w-50-m w-30-l dib bg-washed-blue">
<a href="/" class="f3 f1-ns fw6 hover-blue link pointer black-80 dib ph3">CRUD</a>
</div><div class="w-100 w-50-m w-70-l dib">
<span class="f4 f3-ns fw3 ttu black-80 ph3">crud operations</span>
</div>
</div>
</header>
<section class="flex-auto flex flex-column flex-row-ns">
<div class="pv4 pv2-ns ph2 bg-light-gray">
<a href="/create" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Create user</a>
<a href="/read" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Read user</a>
<a href="/update" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Update user</a>
<a href="/delete" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Delete user</a>
</div>
<DIV class="pv4 pv2-ns ph2 bg-light-gray" style="background-image: linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0)">
<blockquote class="lh-copy">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</blockquote>

</div>
</section>
<footer class="bg-washed-blue pa4 tc">
<span class="f6">&copy; connelblaze</span>
</footer>
</main>
</body>
</html>

for now I’m not going to be using partials so we’ll duplicate the files and mainly just edit the <main> element in your HTML pages.

So go ahead and duplicate the files and change their names so you have:

index.html, create.html, read.html, update.html and delete.html. Save them in admin/ cos we want only admin to o have power to carry out crud, but we need have two `index.html` files. So each section should have a landing page.

Now goto root directory and create an assets directory (you know your root folder right? The 'crud’ folder), this is where all your css,js,img,favicons etc will reside.

Inside assets create img, css directory. Put your css files inside the css directory. I am using tachyons so I’ll just add the file here.

Now go to root directory and create src/main directory and inside the main directory create a main.go file

so your route now looks like this:

full directory

So now it’s to start the go codes. Open the main.go in any IDE or Editor of choice. Now here’s what I’ll propose:

  • Atom very powerful hackable Editor.
  • Goland is dedicated for Go, out of the box. It has some options that the other IDEs cannot give you via the plugin because the other IDEs are dedicated to other languages as primary languages especially IntelliJ related. (Formerly known as Gogland)
  • Webstorm is a lightweight yet powerful JavaScript IDE, perfectly equipped for client-side development and server-side development with Node.js. But could use go via plugin.
  • Ultimate(IDEA) mainly for Java-ish but could use go via plugin.
  • Sublime it’s my best editor, wanna use it for go you could still install plugins for that.

lets go straight to work.

package mainimport ("database/sql""log"_ "github.com/go-sql-driver/mysql""fmt""html/template""net/http")var (ID int64err errordb *sql.DBtempl *template.Template)type PersonData struct {Id intUsername stringPassword stringDescription stringCreated_at mysql.NullTimeUpdated_at mysql.NullTimeAdminD int}func main() {db, err = sql.Open("mysql", "root:xxx@/CRUD")checkErr(err)templ, err = templ.ParseGlob("templates/*.html")checkErr(err)http.HandleFunc("/", index)http.Handle("/assets/", http.FileServer(http.Dir("."))) //serve other files in assets dirhttp.Handle("/favicon.ico", http.NotFoundHandler())fmt.Println("server running on port :8080")http.ListenAndServe(":8080", nil)}func index(res http.ResponseWriter, req *http.Request)  {templ.ExecuteTemplate(res, "index.gohtml", nil)}

now I brought in some things I’ll explain shortly

templ, err = templ.ParseGlob(“templates/*.html”) means every file that ends with .html in templates directory should be parsed to templ

http.Handle(“/favicon.ico”, http.NotFoundHandler()) when go server runs, it also request for the favicon.ico file, so since we don’t have, we could just tell it not to serve it.

the http.HandleFunc registers the handler function for the given pattern. So I passed in a function called index without the () brackets like Java does.

func index(res http.ResponseWriter, req *http.Request)  {
templ.ExecuteTemplate(res, "index.html", nil)
}

The client(browser) sends request, the server respond to the request. This function is executing a template; index.html. And the HandleFunc has register this as the default route with “/”.

So in your terminal navigate to crud/ and type

go run src/main/ main.go

then on your browser goto

http://localhost:8080/

should display

index page

now lets start with the create function

func createUser(res http.ResponseWriter, req *http.Request)  {//insert statement
stmt, err := db.Prepare("INSERT Crud_tb SET username=?, password=?, description=?, created_at=?, updated_at=?, is_admin=?")
//check error
if err != nil {
log.Println(err)
http.Error(res, "there was an error",http.StatusInternalServerError)
return
}
//check if request is post, so until it is don't execute template else when you load template it will first create an empty data and insert into db
if req.Method != "POST" {
templ.ExecuteTemplate(res, "create.html", nil)
return
}
username := req.FormValue("username")
password := req.FormValue("password")
describe := req.FormValue("description")
isAdmin := req.FormValue("admin")
createdAt := time.Now()
updatedAt := time.Now()
var admin_chk int
//since on the html page we have a checkbox with name admin. It's easy to check if it was checked or not in go
if isAdmin == "on" {
admin_chk = 1
} else {
admin_chk = 0
}
var user string
err = db.QueryRow("SELECT username FROM Crud_tb WHERE username=?", username).Scan(&user)
//i want username to be unique
switch {
//is username available?
case err == sql.ErrNoRows:
//no it doesn't exist
//hash password
securedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
rs, err := stmt.Exec(username, securedPassword, describe, createdAt, updatedAt, admin_chk)if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
id, err := rs.LastInsertId()if err != nil {log.Println(err)http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
ID = getID(id).(int64)
res.Write([]byte("user successfully created!"))
fmt.Println("user: ",username," with ID: ",id," successfully created!")
return
case err != nil:
http.Error(res, err.Error(), 500)
return
default:
http.Redirect(res, req, "/create", 301)
}
}

create.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CRUD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/assets/css/tachyons.css">
</head>
<body>
<main class="flex flex-column min-vh-100">
<header class="w-100">
<div class="w-30 dib bg-washed-blue">
<a href="/" class="f3 f2-ns fw6 hover-blue link pointer black-80 dib ph3">CRUD</a>
</div><div class="w-70 dib">
<span class="f5 f3-ns fw3 ttu black-80 ph3">crud operations</span>
</div>
</div>
</header>
<section class="flex-auto flex flex-column flex-row-ns">
<div class="pv4 pv2-ns ph2 bg-light-gray tc w-30-ns">
<div class="dib">
<a href="/create" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Create user</a>
<a href="/read" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Read user</a>
<a href="/update" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Update user</a>
<a href="/delete" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Delete user</a>
</div>
</div>
<div class="pv4 pv2-ns ph2 bg-light-gray w-70-ns" style="background-image: linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0)">
<blockquote class="lh-copy">
<div class="tc">
<form method="post" action="/create">
<div class="pa3"><input type="text" name="username" placeholder="username"></div>
<div><input type="password" name="password" placeholder="password"></div>
<div class="pa3"><input type="text" name="description" placeholder="describe user"></div>
<div>
<input type="checkbox" id="isAdmin" name="admin" />
<label for="isAdmin"><span></span>is admin?</label>
</div>
<div><input type="submit" value="create user"></div>
</form>
</div>
</blockquote>
</div>
</section>
<footer class="bg-light-blue pa4 tc">
<span class="f6">&copy; connelblaze</span>
</footer>
</main>
</body>
</html>

Anyway, time for my break. Need to get some coffee🙂

.

.

  • sql.Open() opens a registered database driver. The Go-MySQL-Driver registers the MySql driver here. The second argument is the DSN (Data Source Name) that defines information about the database connection. It supports the following formats:
  • user@unix(/path/to/socket)/dbname?charset=utf8 user:password@tcp(localhost:5555)/dbname?charset=utf8 user:password@/dbname user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname
  • db.Prepare() returns a SQL operation that is going to be executed. It also returns the execution status after executing SQL.
  • stmt.Exec() executes SQL that has been prepared and stored in stmt.

Note that we use the format =? to pass arguments. This is necessary for preventing SQL injection attacks.

ctr+C to stop server.

Run the server again and click on create user link to see:

create.html

Now what took some of my calories… emm… well. I wanted to display the datas in the db on the html page using html <table> element like a gridview in c#.

So this is what I did

The read function:

func readUser(res http.ResponseWriter, req *http.Request)  {// queryrows, err := db.Query("SELECT * FROM Crud_tb")//was supposed to query specific columns thoif err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
var id int
var username string
var password string
var describe string
var created_at mysql.NullTime
var updated_at mysql.NullTime
var isAdmin int
var ps []PersonData
//loop through the db
for rows.Next() {
err = rows.Scan(&id, &username, &password, &describe, &created_at, &updated_at, &isAdmin)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
ps = append(ps, PersonData{Id: id, Username: username, Password: password, Description: describe, Created_at: created_at, Updated_at: updated_at, AdminD: isAdmin})
}
templ.ExecuteTemplate(res, "read.html", ps)
}

read.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CRUD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/assets/css/tachyons.css">
</head>
<body>
<main class="flex flex-column min-vh-100"><!-- use flex to separate the layouts into diff sections. -->
<header class="w-100">
<div class="w-30 dib bg-washed-blue">
<a href="/" class="f3 f2-ns fw6 hover-blue link pointer black-80 dib ph3">CRUD</a>
</div><div class="w-70 dib">
<span class="f5 f3-ns fw3 ttu black-80 ph3">crud operations</span>
</div>
</div>
</header>
<section class="flex-auto flex flex-column flex-row-ns">
<div class="pv4 pv2-ns ph2 bg-light-gray tc w-30-ns">
<div class="dib">
<a href="/create" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Create user</a>
<a href="/read" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Read user</a>
<a href="/update" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Update user</a>
<a href="/delete" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Delete user</a>
</div>
</div>
<DIV class="pv4 pv2-ns ph2 bg-light-gray overflow-y-scroll w-70-ns" style="background-image: linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0)">
<blockquote class="lh-copy">
<table >
<!-- Table header --> <thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Username</th>
<th scope="col">Password</th>
<th scope="col">Created Date</th>
<th scope="col">updated Date</th>
<th scope="col">Is Admin</th>
</tr>
</thead>
<!-- Table footer --> <tfoot>
<tr>
<td>END</td>
</tr>
</tfoot>
<!-- Table body --> <tbody>
{{ range . }}
<tr>
<td>{{ .Id }}</td>
<td>{{ .Username }}</td>
<td>{{ .Password }}</td>
<td>{{ .Created_at }}</td>
<td>{{ .Updated_at }}</td>
<td>{{ .AdminD }}</td>
</tr>
{{ end }}
</tbody>
</table>
</blockquote>
</div>
</section>
<footer class="bg-light-green pa4 tc">
<span class="f6">&copy; connelblaze</span>
</footer>
</main>
</body>
</html>
  • db.Query() executes SQL and returns a Rows result.
  • I passed the execution via the struct. In go capital letter is public etc. So I range over, that is loop through . the pipeline. You can read more about the period ‘.’

when you run your server again you should get:

read.html

Now add the update function:

func updateUser(res http.ResponseWriter, req *http.Request)  {
//select id's so first loop through the db and get all the ID's so i can display them using the HTML <select> tag
rows, err := db.Query("SELECT id FROM Crud_tb")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
var user = req.FormValue("ids")
var newUsername = req.FormValue("username")
var ps []PersonData
id, err := strconv.Atoi(user)
for rows.Next() {
err = rows.Scan(&id)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
ps = append(ps, PersonData{Id: id})
}
stmt, err := db.Prepare("UPDATE Crud_tb SET username=?, updated_at=? WHERE id=?")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
rs, err := stmt.Exec(newUsername,time.Now(), id)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
affect, err := rs.RowsAffected()
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
if req.Method != "POST" {
templ.ExecuteTemplate(res, "update.html", ps)
return
}
fmt.Println("row :",affect," affected")
}

update.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CRUD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/assets/css/tachyons.css">
</head>
<body>
<main class="flex flex-column min-vh-100"><!-- use flex to separate the layouts into diff sections. -->
<header class="w-100">
<div class="w-30 dib bg-washed-blue">
<a href="/" class="f3 f2-ns fw6 hover-blue link pointer black-80 dib ph3">CRUD</a>
</div><div class="w-70 dib">
<span class="f5 f3-ns fw3 ttu black-80 ph3">crud operations</span>
</div>
</div>
</header>
<section class="flex-auto flex flex-column flex-row-ns">
<div class="pv4 pv2-ns ph2 bg-light-gray tc w-30-ns">
<div class="dib">
<a href="/create" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Create user</a>
<a href="/read" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Read user</a>
<a href="/update" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Update user</a>
<a href="/delete" class="pv2 ph4 f6 fw3 fw6-ns hover-blue link pointer black-80 db">Delete user</a>
</div>
</div>
<DIV class="pv4 pv2-ns ph2 bg-light-gray w-70-ns" style="background-image: linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0)">
<blockquote class="lh-copy">
<div>
<select name="ids">
<option>select user's ID</option>
{{ range . }}
<option value="{{ .Id }}">{{ .Id }}</option>
{{ end }}
</select>
</div>
<div>
<form method="post" action="/update">
<div><input type="text" name="username" placeholder="new username"></div>
<div><input type="submit" value="update user"></div>
</form>
</div>
</blockquote>
</div>
</section>
<footer class="bg-yellow pa4">
<span class="f6">&copy; connelblaze</span>
</footer>
</main>
</body>
</html>

start the server again:

update route

Now delete shouldn’t be hard for you. Don’t mind my footer colors, they have feelings.

Should I say your homework is delete!(with a straight face)

Here’s the whole code:

package mainimport (
"database/sql"
"log"
"golang.org/x/crypto/bcrypt"
_ "github.com/go-sql-driver/mysql"
"time"
"fmt"
"html/template"
"net/http"
"github.com/go-sql-driver/mysql"
"strconv"
)
var (
ID int64
err error
db *sql.DB
templ *template.Template
)
type PersonData struct {
Id int
Username string
Password string
Description string
Created_at mysql.NullTime
Updated_at mysql.NullTime
AdminD int
}
func main() {
db, err = sql.Open("mysql", "root:xxx@/CRUD")
checkErr(err)
templ, err = templ.ParseGlob("templates/*.html")
checkErr(err)
http.HandleFunc("/", index)
http.HandleFunc("/create", createUser)
http.HandleFunc("/read", readUser)
http.HandleFunc("/update", updateUser)
http.HandleFunc("/delete", deleteUser)
http.Handle("/assets/", http.FileServer(http.Dir("."))) //serve other files in assets dir
http.Handle("/favicon.ico", http.NotFoundHandler())
fmt.Println("server running on port :8080")
http.ListenAndServe(":8080", nil)
}
func index(res http.ResponseWriter, req *http.Request) {
templ.ExecuteTemplate(res, "index.gohtml", nil)
}
func createUser(res http.ResponseWriter, req *http.Request) {
//insert into db
stmt, err := db.Prepare("INSERT Crud_tb SET username=?, password=?, description=?, created_at=?, updated_at=?, is_admin=?")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
if req.Method != "POST" {
templ.ExecuteTemplate(res, "create.html", nil)
return
}
username := req.FormValue("username")
password := req.FormValue("password")
describe := req.FormValue("description")
isAdmin := req.FormValue("admin")
createdAt := time.Now()
updatedAt := time.Now()
var admin_chk int
if isAdmin == "on" {
admin_chk = 1
} else {
admin_chk = 0
}
var user string
err = db.QueryRow("SELECT username FROM Crud_tb WHERE username=?", username).Scan(&user)
switch {
//username is available
case err == sql.ErrNoRows:
securedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
rs, err := stmt.Exec(username, securedPassword, describe, createdAt, updatedAt, admin_chk)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
id, err := rs.LastInsertId()
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
ID = getID(id).(int64)
res.Write([]byte("user successfully created!"))
fmt.Println("user: ",username," with ID: ",id," successfully created!")
return
case err != nil:
http.Error(res, err.Error(), 500)
return
default:
http.Redirect(res, req, "/create", 301)
}
}
func readUser(res http.ResponseWriter, req *http.Request) {
// query
rows, err := db.Query("SELECT * FROM Crud_tb")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
var id int
var username string
var password string
var describe string
var created_at mysql.NullTime
var updated_at mysql.NullTime
var isAdmin int
/*if req.Method != "POST" { }*/ var ps []PersonData for rows.Next() {
err = rows.Scan(&id, &username, &password, &describe, &created_at, &updated_at, &isAdmin)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
ps = append(ps, PersonData{Id: id, Username: username, Password: password, Description: describe, Created_at: created_at, Updated_at: updated_at, AdminD: isAdmin})
//return
}
templ.ExecuteTemplate(res, "read.html", ps)
}
func updateUser(res http.ResponseWriter, req *http.Request) {
//select id's
rows, err := db.Query("SELECT id FROM Crud_tb")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
var user = req.FormValue("ids")
var newUsername = req.FormValue("username")
var ps []PersonData
id, err := strconv.Atoi(user)
for rows.Next() {
err = rows.Scan(&id)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
ps = append(ps, PersonData{Id: id})
}
stmt, err := db.Prepare("UPDATE Crud_tb SET username=?, updated_at=? WHERE id=?")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
rs, err := stmt.Exec(newUsername,time.Now(), id)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
affect, err := rs.RowsAffected()
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
if req.Method != "POST" {
templ.ExecuteTemplate(res, "update.html", ps)
return
}
fmt.Println("row :",affect," affected")
}
func deleteUser(res http.ResponseWriter, req *http.Request) {
//select id's
rows, err := db.Query("SELECT id FROM Crud_tb")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusNoContent)
return
}
var user = req.FormValue("ids")
var ps []PersonData
id, err := strconv.Atoi(user)
for rows.Next() {
err = rows.Scan(&id)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
ps = append(ps, PersonData{Id: id})
}
// delete
stmt, err := db.Prepare("delete from Crud_tb where id=?")
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
rs, err := stmt.Exec(id)
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
affect, err := rs.RowsAffected()
if err != nil {
log.Println(err)
http.Error(res, "there was an error", http.StatusInternalServerError)
return
}
if req.Method != "POST" {
templ.ExecuteTemplate(res, "delete.html", ps)
return
}
fmt.Println("row :",affect," affected")
}
func getID(id int64) interface{} {
return id
}
func checkErr(err error) {
if err != nil {
log.Println(err)
}
}

I used checkErr() initially to handle all my error’s but was adviced not to, why? Read About It.

Now this is not the best approach, but it will set you in a good path. Learning never stops, the day you stop learning is the day you die!!!

Golang is a programming language that has it’s own language so sometimes I’m confuse what to call a process or explain what’s going on cos I could “it acts like a class” but that won’t be the right language to use.

My next post will be to add session and cookies.

You can buy me a coffee.

STAY SAFE.

--

--

Connel Asikong

Programmer, Designer, Promoter, music lover, God fearer. thrilled about technology. wish I could help and do more.