{"id":14068340,"url":"https://github.com/beerda/crudtable","last_synced_at":"2026-01-05T05:58:40.311Z","repository":{"id":163974701,"uuid":"254039078","full_name":"beerda/crudtable","owner":"beerda","description":"\"crudtable\" is an R package that provides an easy tabular data input user interface in Shiny web applications. With crudtable, all the user CRUD operations on dataset (Create, Read, Update, Delete) may be easily achieved.","archived":false,"fork":false,"pushed_at":"2022-12-01T09:44:25.000Z","size":246,"stargazers_count":10,"open_issues_count":3,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-04T09:39:14.911Z","etag":null,"topics":["crud","crud-api","database-access","r","shiny"],"latest_commit_sha":null,"homepage":"","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beerda.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-08T09:11:18.000Z","updated_at":"2024-08-13T13:55:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"2e18852d-0a2b-4b6d-97f8-568a1ea14ee4","html_url":"https://github.com/beerda/crudtable","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/beerda/crudtable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beerda%2Fcrudtable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beerda%2Fcrudtable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beerda%2Fcrudtable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beerda%2Fcrudtable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beerda","download_url":"https://codeload.github.com/beerda/crudtable/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beerda%2Fcrudtable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267803984,"owners_count":24146527,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crud","crud-api","database-access","r","shiny"],"created_at":"2024-08-13T07:06:06.482Z","updated_at":"2026-01-05T05:58:40.301Z","avatar_url":"https://github.com/beerda.png","language":"R","readme":"---\noutput:\n    md_document:\n        variant: gfm\n---\n\n```{r setup, include=FALSE}\nknitr::opts_chunk$set(echo = FALSE)\n\n\nreadExample \u003c- function(filename, from=NULL, to=NULL) {\n    cont \u003c- readLines(paste0('inst/examples/', filename))\n    \n    if (!is.null(from)) {\n        from \u003c- grep(paste0('^# ', from, '\\\\. '), cont)\n        from \u003c- from[1]\n        from \u003c- from + 2\n        while (trimws(cont[from]) == '' \u0026\u0026 from \u003c length(cont)) {\n            from \u003c- from + 1\n        }\n    } else {\n        from \u003c- 1\n    }\n    \n    if (!is.null(to)) {\n        to \u003c- grep(paste0('^# ', to, '\\\\. '), cont)\n        to \u003c- to[1]\n        to \u003c- to - 2\n        while (trimws(cont[to]) == '' \u0026\u0026 to \u003e 1) {\n            to \u003c- to - 1\n        }\n    } else {\n        to \u003c- length(cont)\n    }\n    \n    cont \u003c- cont[seq.int(from, to)]\n    \n    cat('```\\n')\n    cat(cont, sep='\\n')\n    cat('```\\n')\n}\n```\n\n\n![crudtable build on travis-ci.org](https://travis-ci.org/beerda/crudtable.svg?branch=master)\n![crudtable build on appveyor.com](https://ci.appveyor.com/api/projects/status/github/beerda/crudtable?branch=master\u0026amp;svg=true)\n![crudtable code coverage](https://codecov.io/gh/beerda/crudtable/branch/master/graph/badge.svg)\n![crudtable in CRAN](http://www.r-pkg.org/badges/version/crudtable)\n\n\n# crudtable\n\n**crudtable** is an [R](https://www.r-project.org/) package that makes it easy to develop an\neditable data table in [Shiny](https://shiny.rstudio.com/) web applications. With **crudtable**,\nthe following operations may be easily achieved:\n\n* *CRUD* - **C**reate, **R**read, **U**pdate and **D**elete of data records in\n  [DT](https://cran.r-project.org/web/packages/DT/index.html) DataTable and a modal edit dialog\n  window;\n* *validation* - ensuring the correct format of the user input;\n* *database access* - storing the data into a database via the standardized [DBI](https://www.r-dbi.org/) package\n  for [R](https://www.r-project.org/) or to a file.\n  \n\n\n## Live Demo\n\nSee the [live demo](https://beerda.shinyapps.io/crudtable/) of the **crudtable** package.\n\n  \n\n## Getting Started\n\nTo install the latest development version from GitHub:\n\n```\ninstall.packages(\"remotes\")\nremotes::install_github(\"beerda/crudtable\")\n```\n\n\n## A Minimal Working Example\n\nA minimal Shiny app that uses **crudtable**:\n\n```{r, results='asis'}\nreadExample('minimal/app.R')\n```\n\nFirst, a Data Access Object (DAO) is created with `dataFrameDao`.\nDAO is a list structure that provides data access functions to the `crudTable` user interface.\nIn this example, a simple DAO is created that works with an in-memory data frame `CO2`. \nAlternatively, an SQL database may be connected with **crudtable**'s `sqlDao` DAO.\n\nThe UI part consists of `crudTableUI` that uses\n[DT](https://cran.r-project.org/web/packages/DT/index.html)'s `DataTable` to view the dataset.\nThe **crudtable** UI also provides the *New record*, *Edit record* and *Delete record* buttons.\n\nThe server part consists of the call of the `crudTable` module that connects the `crudTableUI`\nwith the DAO.\n\n\n\n## An Advanced Example\n\nAll the aspects and capabilities of the **crudtable** package will be shown in this advanced\nexample, which covers:\n\n* access to an SQLite data table;\n* custom input form user interface;\n* validation of the user input;\n* how to store values that are, rather than directly entered by the user, obtained programmatically.\n\nFirst of all, let us import all the needed packages:\n\n```{r, results='asis'}\nreadExample('advanced/app.R', NULL, 1)\n```\n\nWe need `DBI` and `RSQLite` for database access, and `shinyjs` for JavaScript support. \n\nNext, we initialize the in-memory SQLite database engine and register the connection cleanup hook on\nstop of Shiny. We also create an empty data frame `df` with columns: `date`, `service`,\n`amount`, `discount`, `total` and `paid`. This data frame is saved into SQLite as table `'invoice'`.\nWe also create a Data Access Object (DAO) `dao` by calling the `sqlDao()` function:\n\n```{r, results='asis'}\nreadExample('advanced/app.R', 1, 2)\n```\n\nNote also the `typecast` argument of the `sqlDao()` call: it causes the internally numeric attribute\n`date` to be type casted into `Date`. Such workaround is needed because the DBI interface does not\nsupport such complex data types as `Date`.\n\nFor our convenience, we also create a constant list of service prices that will be used to populate\nthe select box with values:\n\n```{r, results='asis'}\nreadExample('advanced/app.R', 2, 3)\n```\n\nWe also want a custom edit dialog window with some pre-defined values and well defined ranges for\nnumeric inputs. We also add two read only input lines that will present some computed values to\nthe user. For that, we use the `disabled()` function of the `shinyjs` package. Note also the\nnamespacing of the input IDs by the `ns()` function, which is mandatory:\n\n```{r, results='asis'}\nreadExample('advanced/app.R', 3, 4)\n```\n\nAfter the edit form UI is defined, we need to create the server part of the form handler. Since\nwe want to perform a lot of custom functionality, we code the server part in two steps. First, a\ndefault form server handler is initialized by calling the `formServerFactory()` function:\n\n```{r, results='asis'}\nreadExample('advanced/app.R', 4, 5)\n```\n\n`formServerFactory()` requires `dao` and a definition of `validators`. Validator is a mechanism\nfor restricting the input to certain criteria. If the user insert invalid input, an error message\nis shown and the edit form dialog can not be submitted. In the piece of code above, we define two\ntypes of validators: a custom validator bound to the `amount` data input, which tests the oddness\nof the value. The second validator is `filledValidator` that ensures the data inputs are filled.\n`filledValidator` is bound to all data inputs - we call `names(dao$getAttributes())` instead of\nenumerating names of all data columns.\n\nNow we can define our server-side handler of the edit form. First, `defaultFormServer` handler\nmust be called, which returns a list of useful reactive values and triggers. After that, we can\nprovide an observer that computes the read only inputs of the form. Note that we need to observe\nthe `res$loadTrigger()` here, which triggers everytime the data get loaded into the edit form.\nThis ensures that the computed values are initialized properly too. Note also that the server-side\nhandler must return the `res`, which is the result of `defaultFormServer`:\n\n```{r, results='asis'}\nreadExample('advanced/app.R', 5, 6)\n```\n\nAnd that's nearly all. The last step is the initialization of the Shiny app. We use `crudTableUI`\non the client side and we call the `crudTableServer` function on the server side. The latter gets `dao`,\n`myFormUI` and `myFormServer` as arguments. Note also that the `crudTableServer` function returns\na reactive value that changes everytime the CRUD table widget changes the data. That reactive value\ncan be used to trigger update of output widgets that rely on the data, as can be seen below.\n\n```{r, results='asis'}\nreadExample('advanced/app.R', 6, NULL)\n```\n\nNote that it is not needed to call the `useShinyjs()` function in the UI of the Shiny application\nsince the **crudtable** package does it internally by itself.\n\nThe complete advanced example is as follows:\n\n```{r, results='asis'}\nreadExample('advanced/app.R')\n```\n\nEnjoy.\n","funding_links":[],"categories":["R"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeerda%2Fcrudtable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeerda%2Fcrudtable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeerda%2Fcrudtable/lists"}