I have an UI application that is based on clojurescript reagent and re-frame. I learned something on this spending hours, but I'm not able to figure out what's happening there and how to fix it. I have an issue that you can see in the animated image below. I need to avoid clearing fields on resize.
At first I need to find out the right approach of doing this. I'm not sure what would be the right one. I would like to make at least single field to avoid resetting on resize. So far I tried to define global atom like this.
(def program-name-state (r/atom ""))
Then I use it in some function (I assume this function obviously resets the values).
reset-fn (fn [& _]
(reset! *processing-types (:processingTypes program))
(reset! *form program)
(reset! program-name-state (:name program)))
Then I use it like this in the input
control.
[:div.form-group
[:label.control-label.col-sm-3.col-md-2.col-lg-1 (t :name)]
[:div.col-sm-9.col-md-10.col-lg-11
[:input.form-control
{:type "text"
:value @program-name-state
:on-change #(reset! program-name-state (ue/value %))}]]]
I was suggested to do it that way by GPT-4o. And this doesn't work. Could please anyone shed some light on how to achieve what I want?
--UPDATE-- The file that describes the right pane of the tab depicted -- With original code commented out
--UPDATE--
react-split-pane is used like this.
(ns oms-ui.util.split-pane
(:require ["react-split-pane$default" :as SplitPane]
[reagent.core :as r]))
(def split-pane (r/adapt-react-class SplitPane))
And here is the page that contains the right pane
(ns oms-ui.view.workflow.programs
(:require-macros [reagent.ratom :refer [reaction]])
(:require [goog.dom :as gdom]
[goog.dom.classlist :as gclasslist]
[goog.events.KeyCodes :as KeyCodes]
[goog.style :as gstyle]
[clojure.string :as s]
[reagent.core :as r]
[re-frame.core :as rf]
[oms-ui.conf :as conf]
[oms-ui.routes :as routes]
[oms-ui.localization :as localize]
[oms-ui.view.workflow.modals :as modals]
[oms-ui.view.workflow.context-menu :as context-menu]
[oms-ui.view.workflow.modals :as modal-workflow]
[oms-ui.view.form.program :as fp]
[oms-ui.widgetmon :as wcommon]
[oms-ui.widget.button :as w-button]
[oms-ui.util :as u]
[oms-ui.util.dom :as ud]
[oms-ui.util.vectors :as v :refer [remove-item-from-vector]]
[oms-ui.utilmon :as c :refer [set-timeout]]
[oms-ui.util.string :as us]
[oms-ui.util.split-pane :as sp]))
(rf/reg-sub
::split-pane-width
(fn [db _]
(get-in db [:split-panes :width])))
(rf/reg-event-db
::set-split-pane-width
(fn [db [_ value]]
(assoc-in db [:split-panes :width] value)))
(defn new-program [new-program-name]
{:name new-program-name
:program {:executable "" :parameters "" :logFile "" :errorCheckType "file" :workingPath ""}
:options {:jetFormOrResponse true :oneInstanceOnly false :isPlugin false}
:processingTypes []
:errorChecks {:file {:fileName "error.log" :message "Error"} :returnCode 0 :consoleMessage "Error"}})
(def *scroll-position-state (r/atom 0)) ; FUTURE: Move this to the base +add cleanup
(defn page [{:keys [show-modal-fn hide-modal-fn show-ctx-menu-fn] :as context}]
(let [active-item-state (reaction (get @(rf/subscribe [:active-page]) 2))
locale-sub (rf/subscribe [:current-locale])
programs-sub (rf/subscribe [:server-programs])
*programs (reaction (us/sort-by-keyfn :name @programs-sub))
*program-names (reaction (vec (map :name @*programs)))
*programs-split-pane-width (rf/subscribe [::split-pane-width])
show-context-menu (fn [event selected-program ctx]
(show-ctx-menu-fn event [context-menu/programs-menu selected-program (merge context ctx)]))]
(fn [_show-modal-fn _hide-modal-fn]
(let [programs @*programs
locale @locale-sub
programs-by-name (u/index #(s/lower-case (:name %)) programs)
program-names @*program-names
program-names-set (set (map #(s/lower-case %) program-names))
validate-name-fn #(when (contains? program-names-set %)
(localize/t locale :workflow.programs.validate/program-with-this-name-exists))
active-program-name @active-item-state
select-program-fn (fn
([] (routes/go-to! (routes/workflow-tab {:tab "programs"})))
([program-name] (routes/go-to! (routes/workflow-tab-item "programs" program-name))))
[validate-fn program-widget program-buttons]
(fp/get-form
locale active-program-name
(if (nil? active-program-name)
nil
(get programs-by-name (s/lower-case active-program-name)))
(fn [origin-name name save-data]
(rf/dispatch
[:update-server-program
origin-name
save-data
(fn []
(rf/dispatch [:set-nav-away-callback])
(select-program-fn name))]))
validate-name-fn show-modal-fn hide-modal-fn)
add-program-fn (fn [& _] (validate-fn
{:ok-fn (fn [] (js/setTimeout
(fn []
(rf/dispatch [:set-nav-away-callback])
(show-modal-fn :create-program
(modals/enter-name
{:title-text (localize/t locale :modal.workflow.add.program/title)
:submit-button-text (localize/t locale :modal.workflow.add.program/create-button)
:label-text (localize/t locale :modal.workflow.add.program/label)
:validate-fn validate-name-fn
:result-callback (fn [program-name]
(rf/dispatch [:create-server-program
(new-program program-name)
#(select-program-fn program-name)]))
:hide-fn hide-modal-fn})))
500))}))
delete-program-fn (fn [program-name]
(show-modal-fn :delete-program
(modal-workflow/delete-program
{:program-name program-name
:locale locale
:hide-fn hide-modal-fn
:tasks-sub (rf/subscribe [:tasks])
:delete-fn (fn []
(rf/dispatch [:set-nav-away-callback])
(rf/dispatch [:delete-server-program
program-name]
(select-program-fn)))})))
programs-split-pane-width (or @*programs-split-pane-width conf/WORKFLOW-SPLIT-PANE-DEFAULT-WIDTH)]
(when-not (nil? active-program-name)
(rf/dispatch [:set-nav-away-callback validate-fn]))
[:div.workflow.page.programs
[:div.main-toolbar.btn-toolbar
[:div.btn-group.btn-group-sm
[w-button/toolbar-button :icon-name "plus" :icon-class "green"
:label (localize/t locale :workflow.button/add)
:on-click add-program-fn]
[w-button/toolbar-button :icon-name "remove" :icon-class "red"
:label (localize/t locale :workflow.button/delete)
:disabled? (clojure.string/blank? active-program-name)
:on-click #(delete-program-fn active-program-name)]]
[:div.btn-group.btn-group-sm
[w-button/toolbar-button :icon-name "refresh"
:tooltip (localize/t locale :tooltip.workflow.programs/refresh)
:on-click #(rf/dispatch [:refresh :workflow])]]
[program-buttons]]
[:div.panes
[sp/split-pane
{:min-size conf/WORKFLOW-SPLIT-PANE-MIN-WIDTH
:max-size conf/WORKFLOW-SPLIT-PANE-MAX-WIDTH
:default-size programs-split-pane-width
:on-change #(rf/dispatch [::set-split-pane-width %])
:split "vertical"}
[:div.left-pane
(wcommon/events-wrapper
[:ul.nav.nav-pills.pills-focusable.nav-stacked.focused
; tab-index required for keypress handling
{:tab-index 0}
(for [{:keys [name] :as _program} programs]
(wcommon/events-wrapper
[:li.no-selection (merge {:id (str "li-" name) :role "presentation"}
(when (= name active-program-name) {:class "active"}))
[:a {:id (str "program-" name)
:data-program-name name
:href (routes/workflow-tab-item "programs" name)} name]]
{:right-click-fn #(show-context-menu % name
{:add-program-fn add-program-fn
:delete-program-fn (fn [_] (delete-program-fn name))})}
name))]
{:did-mount-fn (fn [_component node]
(set! (.-scrollTop node) @*scroll-position-state)
(ud/focus node)
(u/execute-until
(fn []
(when-let [q (gdom/findNode node #(and (= "a" (s/lower-case (.-nodeName %)))
(= active-program-name
(-> % gdom/getElement
(.getAttribute "data-program-name")))))]
(gstyle/scrollIntoContainerView (gdom/getElement q) node false)
true))))
:scroll-fn #(reset! *scroll-position-state (.-scrollTop (u/target %)))
:focus-fn #(gclasslist/add %2 "focused")
:blur-fn #(gclasslist/remove %2 "focused")
:key-down-fn (fn [event]
(let [program-names @*program-names
active-program-name @active-item-state]
(when-not (s/blank? active-program-name)
(condp = (.-keyCode event)
KeyCodes/UP
(let [item-idx (v/index-of program-names active-program-name)
new-idx (dec item-idx)]
(when (>= new-idx 0)
(select-program-fn (get program-names new-idx))))
KeyCodes/DOWN
(let [item-idx (v/index-of program-names active-program-name)
new-idx (inc item-idx)]
(when (and (>= new-idx 0) (< new-idx (count program-names)))
(select-program-fn (get program-names new-idx))))
KeyCodes/HOME
(select-program-fn (first program-names))
KeyCodes/END
(select-program-fn (last program-names))
KeyCodes/F5
(rf/dispatch [:refresh :workflow])
KeyCodes/INSERT
(when (.-ctrlKey event)
(add-program-fn))
KeyCodes/DELETE
(delete-program-fn active-program-name)
nil)))
(u/prevent-event event))})]
[:div.right-pane
[program-widget]]]]]))))