I have a table created using seesaw.swingx and i want to refresh the data in the rows of the table (or even clearing the entire table and giving new data to it will do). How do i achieve this, I know i might have to use table/table-model, but how do i give this table model to my current table?
my table is created as
(swingx/table-x :id :data-table
:horizontal-scroll-enabled? true
:model [:columns [{:key :first-name :text "First Name"}
{:key :last-name :text "Last Name"}]
:rows (get-data)]))
EDIT:
So this is my handler where i want to update my table
(defn- return-movie-handler
[event]
(let [root (seesaw/to-root event)
table (seesaw/select root [:#data-table])]
;some code
(seesaw/replace! root table (get-table-model))))))
and my get-table-model is
(defn- get-table-model
[]
(seesaw.table/table-model :columns [{:key :first-name :text "First Name"}
{:key :last-name :text "Last Name"}]
:rows (get-data)))
doing this i get an exception java.lang.IllegalArgumentException: No implementation of method: :make-widget* of protocol: #'seesaw.make-widget/MakeWidget found for class: seesaw.table.proxy$javax.swing.table.DefaultTableModel
you may use replace! , http://daveray.github.io/seesaw/seesaw.core-api.html#seesaw.core/replace!
(replace! Container Old widget Table Model)
Here is updated code I base on your code. I tested on my local ,works good.
(use 'seesaw.core)
(defn- get-table-model
[a b]
(seesaw.core/table :model [:columns [ :first-name :last-name]
:rows [[ a b]]]))
(def base_frame (frame :title "Base Frame" :content (vertical-panel :items [(border-panel :north (get-table-model "a" "b" ) :id :panel_id)])))
(show! base_frame)
(pack! base_frame)
(replace! (select base_frame [:#panel_id]) (first (select base_frame [:<javax.swing.JTable>])) (get-table-model "C" "D") )
It's a bit late, but you can also use (config! (select root [:#data-table]) :model new-model), having kept the model in an atom or using a generator function. Much simpler than (replace!) imo.
Related
I started to learn Clojure this week, specifically I'm learning web development with Luminus. Since I want to understand the CRUD process, I setup a function to save my post into the DB:
(defn save-post! [{:keys [params]}]
(if-let [errors (validate-post params)]
(-> (response/found "/posts")
(assoc :flash (assoc params :errors errors)))
(do
(db/save-post!
(assoc params :created_at (java.util.Date.)))
(response/found "/posts"))))
The query is pretty basic:
-- :name save-post! :! :n
-- :doc creates a new post record
INSERT INTO posts
(title, body, active, created_at)
VALUES (:title, :body, :active, :created_at)
but the HTML form has a checkbox field:
<input type="checkbox" name="active" value="1">Published<br />
and when it is not selected, the field is not send and the SQL insert query sends the error message "No active field". How can I check if the element "active" is set and add it to "params" as true or false?
Something like:
(assoc params :active (if (nil? params/active) false true))
after the ":created_at (java.util.Date.)" line.
How can I check if the element "active" is set and add it to "params" as true or false?
Looks like your code isn't far from working. You'll need to check the params map to see if it has the checkbox's value. If (:active params) is equal to "1" when the checkbox is checked, then you might do something like this:
(assoc params :active (= "1" (:active params)))
But what this is really trying to do is update a particular value in the map, which can be done more idiomatically:
(update params :active #(= "1" %))
Where the final argument is a function that takes any current value of the keyword and returns the new value.
Another potential gotcha: you may not want to use the params map as direct input to your DB query, because it could very easily contain keys/values that you don't want or expect. It'd be safer to pull only the values you need from it explicitly e.g. (select-keys params [:title :body :active]).
(def params {:active "1", :admin true}) ;; wouldn't want admin to leak through!
(-> params
(select-keys [:title :body :active])
(assoc :created_at (java.util.Date.))
(update :active #(= "1" %)))
;;=> {:active true, :created_at #inst "2017-10-09T20:16:06.167-00:00"}
I have defined record to store User details and Address Details.
(defrecord User [id name address])
(defrecord Address [id location street city state])
(def usr (User. 1 "Abc"
(Address. 1 "Location 1" "Street" "NY" "US")))
I have updated "name" to "BCD" using the below code
(assoc usr :name "BCD")
Output:
#async_tea_party.core.User{:id 1, :name "BCD", :address #async_tea_party.core.Address{:id 1, :location "Location 1", :street "Street", :city "NY", :state "US"}}
(usr)
OutPut:
#async_tea_party.core.User{:id 1, :name "Abc", :address #async_tea_party.core.Address{:id 1, :location "Location 1", :street "Street", :city "NY", :state "US"}}
New value of name field has not updated and It still shows old value.
How can I update "name" field permanently in "User" record?
(def usr (User...)) is kind of immutable. You cannot change it.
When you do (assoc usr :name "BCD") you are not changing it. You create a new one. In order to do what you want you need an atom.
(def usr (atom (User. 1 "Abc"
(Address. 1 "Location 1" "Street" "NY" "US"))))
(:name #usr) ;; "Abc"
(swap! usr assoc :name "BCD")
(:name #usr) ;; "BCD"
This is called immutability and is one of the main reasons for me to like clojure so much.
To understand the reasoning why this behaviour is so beneficial, reading values and state really helped me
I play around with clojure and its korma library using an sqlite3 database on windows. I follow an example of the 7web book. It introduces the select* function and its friends.
But using the fields function adds fields instead of restricting.
;; models.clj
(defentity issue
(entity-fields :id :project_id :title :description :status)
(has-many comment))
;; repl
test=> (-> (select* issue)
#_=> (fields :title)
#_=> (as-sql))
"SELECT \"issue\".\"id\", \"issue\".\"project_id\", \"issue\".\"title\", \"issue\".\"description\", \"issue\".\"status\", \"issue\".\"title\" FROM \"issue\""
Did i miss anything?
Like mentioned in issue #251 the reason is the entity-fields expression. It defines the default fields for queries. The fields function adds more fields to the defaults. Works as designed.
Therefore I removed entity-fields within defentity.
;; models.clj
(defentity issue
(has-many comment))
;; repl
test=> (-> (select* issue)
#_=> (fields :title)
#_=> (as-sql))
"SELECT \"issue\".\"title\" FROM \"issue\""
test=> (-> (select* issue)
#_=> (as-sql))
"SELECT \"issue\".* FROM \"issue\""
Suppose I have this vector of maps:
[{:title "Title1" :id 18347125}
{:title "Title2" :id 18347123}
{:title "Title3" :id 18341121}]
And I wish to select the map with :id 18347125, how would I do this?
I've tried
(for [map maps
:when (= (:id map) id)]
map)
This feels a bit ugly and returns a sequence of length one, and I want to return just the map.
IMHO, there are several ways to solve your problem, and the definitely idiomatic way is in the realm of taste. This is my solution where I simply translated "to select maps whose :id is 1834715" into Clojure.
user> (def xs [{:title "Title1" :id 18347125}
{:title "Title2" :id 18347123}
{:title "Title3" :id 18341121}])
#'user/xs
user> (filter (comp #{18347125} :id) xs)
({:title "Title1", :id 18347125})
The :id keyword is a function that looks up itself in a collection passed to it. The set #{18347125} is also a function that tests if a value passed to it equals 18347125. Using a Clojure set as a predicate function allows for a succinct idiom.
I'm not sure if it's the simplest way to write it, but I think this is more clear about your intentions:
(->> maps
(filter #(= (:id %) id))
first)
This doesn't do what you asked for exactly, but might be useful nonetheless:
user=> (group-by :id [{:title "Title1" :id 18347125}
{:title "Title2" :id 18347123}
{:title "Title3" :id 18341121}])
{18347125 [{:title "Title1" :id 18347125}]
18347123 [{:title "Title2" :id 18347123}]
18341121 [{:title "Title3" :id 18341121}]}
Now you can simply look the map up by id. Read more about group-by on clojuredocs, its a very useful function.
Note that it puts the maps inside vectors. This is because group-by is designed to handle grouping (ie multiple items with the same key):
user=> (group-by :id [{:title "Title1" :id 123}
{:title "Title2" :id 123}
{:title "Title3" :id 18341121}])
{123 [{:title "Title1" :id 123} {:title "Title2" :id 123}]
18341121 [{:title "Title3" :id 18341121}]}
If you need to query not just once, but multiple times for maps with specific IDs, I would suggest to make your data types match your use case, i.e. to change the vector into a map:
(def maps-by-id (zipmap (map :id maps) maps))
So now your IDs are the keys in this new map of maps:
user=> (maps-by-id 18347125)
{:title "Title1", :id 18347125}
I am trying to scrape some data from a page with a table based layout. So, to get some of the data I need to get something like 3rd table inside 2nd table inside 5th table inside 1st table inside body. I am trying to use enlive, but cannot figure out how to use nth-of-type and other selector steps. To make matters worse, the page in question has a single top level table inside the body, but (select data [:body :> :table]) returns 6 results for some reason. What the hell am I doing wrong?
For nth-of-type, does the following example help?
user> (require '[net.cgrand.enlive-html :as html])
user> (def test-html
"<html><head></head><body><p>first</p><p>second</p><p>third</p></body></html>")
#'user/test-html
user> (html/select (html/html-resource (java.io.StringReader. test-html))
[[:p (html/nth-of-type 2)]])
({:tag :p, :attrs nil, :content ["second"]})
No idea about the second issue. Your approach seems to work with a naive test:
user> (def test-html "<html><head></head><body><div><p>in div</p></div><p>not in div</p></body></html>")
#'user/test-html
user> (html/select (html/html-resource (java.io.StringReader. test-html)) [:body :> :p])
({:tag :p, :attrs nil, :content ["not in div"]})
Any chance of looking at your actual HTML?
Update: (in response to the comment)
Here's another example where "the second <p> inside the <div> inside the second <div> inside whatever" is returned:
user> (def test-html "<html><head></head><body><div><p>this is not the one</p><p>nor this</p><div><p>or for that matter this</p><p>skip this one too</p></div></div><span><p>definitely not this one</p></span><div><p>not this one</p><p>not this one either</p><div><p>not this one, but almost</p><p>this one</p></div></div><p>certainly not this one</p></body></html>")
#'user/test-html
user> (html/select (html/html-resource (java.io.StringReader. test-html))
[[:div (html/nth-of-type 2)] :> :div :> [:p (html/nth-of-type 2)]])
({:tag :p, :attrs nil, :content ["this one"]})