README
¶
Go bindings for w2ui
This package offers Go bindings for the w2ui JavaScript UI Library.
Features
-
w2gridsupport inJSONmode:- Pagination, sorting, and search;
- Inline editing with typed updates;
- Batch delete;
- Drag and Drop row reordering;
-
w2formsupport inJSONmode:- Record retrieval;
- Form submission (create/update);
-
Dropdowns:
- Reusable across
w2gridandw2formcomponents; - Searchable and dynamic;
- Reusable across
-
SQL Builder integration:
- Translate
w2griddata request into SQL withgo-sqlbuilder;
- Translate
Install
go get github.com/dv1x3r/w2go
Usage
w2go types are JSON-serializable and work seamlessly with frameworks like Echo or Fiber, or standard net/http.
The following examples use Go's standard net/http library: (w http.ResponseWriter, r *http.Request).
w2grid
Get Records
req, err := w2.ParseGridDataRequest(r.URL.Query().Get("request"))
if err != nil {
res := w2.NewErrorResponse(err.Error())
res.Write(w, http.StatusBadRequest)
return
}
// Process the request...
records := []Todo{{ID: 1, Name: "Buy groceries"}}
res := w2.NewGridDataResponse(records, len(records))
res.Write(w)
Save Changes
req, err := w2.ParseGridSaveRequest[Todo](r.Body)
if err != nil {
res := w2.NewErrorResponse(err.Error())
res.Write(w, http.StatusBadRequest)
return
}
// Apply updates for req.Changes slice...
res := w2.NewSuccessResponse()
res.Write(w, http.StatusOK)
Remove Records
req, err := w2.ParseGridRemoveRequest(r.Body)
if err != nil {
res := w2.NewErrorResponse(err.Error())
res.Write(w, http.StatusBadRequest)
return
}
// Apply updates for req.ID slice...
res := w2.NewSuccessResponse()
res.Write(w, http.StatusOK)
Reorder Rows
req, err := w2.ParseGridReorderRequest(r.Body)
if err != nil {
res := w2.NewErrorResponse(err.Error())
res.Write(w, http.StatusBadRequest)
return
}
// Apply updates based on req.RecID, req.MoveBefore and req.Bottom...
res := w2.NewSuccessResponse()
res.Write(w, http.StatusOK)
w2form
Get Record
req, err := w2.ParseFormGetRequest(r.URL.Query().Get("request"))
if err != nil {
res := w2.NewErrorResponse(err.Error())
res.Write(w, http.StatusBadRequest)
return
}
// Process the request based on req.RecID...
record := Todo{ID: 1, Name: "Example"}
res := w2.NewFormGetResponse(record)
res.Write(w)
Save Record
req, err := w2.ParseFormSaveRequest[Todo](r.Body)
if err != nil {
res := w2.NewErrorResponse(err.Error())
res.Write(w, http.StatusBadRequest)
return
}
// Insert or update based on req.RecID...
res := w2.NewFormSaveResponse(req.RecID)
res.Write(w)
Dropdown
Get Records
req, err := w2.ParseDropdownRequest(r.URL.Query().Get("request"))
if err != nil {
res := w2.NewErrorResponse(err.Error())
res.Write(w, http.StatusBadRequest)
return
}
// Process the request based on req.Max and req.Search...
records := []w2.Dropdown{}
res := w2.NewDropdownResponse(records)
res.Write(w)
SQL Builder
Use w2sqlbuilder with github.com/huandu/go-sqlbuilder to apply filters, sorters, limits, and updates.
Apply Filters
req, _ := w2.ParseGridDataRequest(r.URL.Query().Get("request"))
// Create a SelectBuilder
sb := sqlbuilder.NewSelectBuilder()
sb.Select("t.id", "t.name")
sb.From("todo as t")
// Define the w2ui field to database field name mapping.
mapping := map[string]string{
"id": "t.id",
"name": "t.name",
}
// Apply query filters based on the request and mapping.
w2sqlbuilder.Where(sb, req, mapping)
Apply Sorters
req, _ := w2.ParseGridDataRequest(r.URL.Query().Get("request"))
// Create a SelectBuilder
sb := sqlbuilder.NewSelectBuilder()
sb.Select("t.id", "t.name")
sb.From("todo as t")
// Define the w2ui field to database field name mapping.
mapping := map[string]string{
"id": "t.id",
"name": "t.name",
}
// Apply query sorters based on the request and mapping.
w2sqlbuilder.OrderBy(sb, req, mapping)
Apply Limits
req, _ := w2.ParseGridDataRequest(r.URL.Query().Get("request"))
// Create a SelectBuilder
sb := sqlbuilder.NewSelectBuilder()
sb.Select("t.id", "t.name")
sb.From("todo as t")
// Apply limit and offset based on the request.
w2sqlbuilder.Limit(sb, req)
w2sqlbuilder.Offset(sb, req)
Apply Updates
Use this approach to apply inline changes to editable w2grid fields.
To track whether a field was included in the request, wrap it with the w2.Field type:
type Todo struct {
ID int `json:"id"`
Name string `json:"name"`
Description w2.Field[string] `json:"description"`
Quantity w2.Field[int] `json:"quantity"`
}
Update functions:
w2sqlbuilder.SetField: updates the field only if a value is provided. Uses null if the value is empty.w2sqlbuilder.SetFieldNoNull: updates the field only if a value is provided. Uses the zero value if value is empty.
req, _ := w2.ParseGridSaveRequest[Todo](r.Body)
for _, change := range req.Changes {
ub := sqlbuilder.Update("todo")
ub.Where(ub.EQ("id", change.ID))
w2sqlbuilder.SetField(ub, change.Description, "description")
w2sqlbuilder.SetField(ub, change.Quantity, "quantity")
// ...
}
Utils
ReorderArray
Use w2sort.ReorderArray to reorder a slice of integers based on w2grid drag and drop:
req, _ := w2.ParseGridReorderRequest(r.Body)
// ids represents the current order (e.g., from database)
ids := []int{1, 2, 3, 4, 5}
// Reorder the slice based on the drag and drop request
if err := w2sort.ReorderArray(ids, req); err != nil {
// handle error (e.g., id not found in slice)
}
// ids now contains the new order
// Persist the new order to the database...
Example
Run a full CRUD demo using in-memory SQLite:
go run example/main.go
Starts the server on http://localhost:3000
License
Licensed under the MIT license.