Get the value from form while clicking on submit - clojurescript

(defn text-input
[label]
[:div.row
[:div.col-md-2
[:span label]]
[:div.col-md-3
[:input {:type "text" :class "form-control" :style {:border "1px solid red"}}]]])
(defn hello-world
[]
[:div.page-header
[:h1 "Reagent Form"]
[text-input "First name" ]
[text-input "last name"]
[text-input "mobile number"]
[text-input "address"]
[:button {:type "submit" :class "btn btn-default"
:on-click #(.log js/console (clj->js #state))} "Submit"] ])

If you want to print the value from the event you can use an on-click handler like this:
(fn [event] (.log js/console (-> event .-target .-value)))
So use that instead of #(.log js/console (clj->js #state)).
See http://reagent-project.github.io/ for examples of using the target value. E.g.,
(ns example
(:require [reagent.core :as r]))
(defn atom-input [value]
[:input {:type "text"
:value #value
:on-change #(reset! value (-> % .-target .-value))}])
(defn shared-state []
(let [val (r/atom "foo")]
(fn []
[:div
[:p "The value is now: " #val]
[:p "Change it here: " [atom-input val]]])))

Related

How do I make text within a container centered instead of floating at the top?

I have a container with two columns, an image on the left and text on the right (I'm making a landing page based on the one from ClojureBridge London). Right now the text is at the top of the column. How do I bring it down to the middle? (I'm totally new to all this so thanks for your patience).
As you can see, I tried to add a bunch of spans and empty paragraphs and they didn't do anything. What am I supposed to be doing here?
[:div {:class "container"}
[:div {:class "box"}
[:div {:class "columns"}
[:div {:class "column"}
[:figure {:class "image"}
[:img {:src "img/picture.png"}]]]
[:div {:class "column"}
[:div {:class "content"}
[:span]
[:h2 "This is a header"]
[:p "This is a paragraph."]
[:p "More paragraph."]
[:p
[:a {:href "https://clojurebridgelondon.github.io/organise-clojurebridge-london/"
:target "_blank"}
"Example of a link"]]
[:span]
[:p " "]]
[:span]
[:div {:class "content"}]]]]]

Create popup with Clojurescript

I am new to Clojurescript and trying to test basic functions -- in this case creating a popup.
This code displays the button:
[:div {:class "dim-a item"}
[dc :div {:dc-id 3 :hidden false}
[:div {:class "item"
:style {:border "1px solid #D4D4D4"
:border-radius "3px"}}
[:div [bp/icon {:icon "grid-view" :style {:color "#555555"}}] [:br] "Color"]]]]
This is what I tried to create the popup, but it does not compile.
[:div {:class "dim-a item"}
[dc :div {:dc-id 3 :hidden false}
[:div {:class "item"
:style {:border "1px solid #D4D4D4"
:border-radius "3px"}}
[:div [bp/icon {:icon "grid-view" :style {:color "#555555" {:on-click #(reset! popup-shown false)}
[:div.alert.alert-info
[:div "Hello!"]]}}] [:br] "Color"]]]]
Can anyone see what I'm doing wrong?
EDIT:
When I try this:
[:div {:class "dim-a item"}
[dc :div {:dc-id 3 :hidden false}
[:div {:class "item"
:style {:border "1px solid #D4D4D4"
:border-radius "3px"}}
[:div [bp/icon {:icon "grid-view"
:style {:color "#555555" {:on-click #(reset! popup-shown false)}}}
[:div.alert.alert-info
[:div "Hello!"]]] [:br] "Color"]]]]
I get this:
------ ERROR -------------------------------------------------------------------
File: /Users/reallymemorable/Documents/m/renderer.cljs:750:100
--------------------------------------------------------------------------------
747 | :style {:border "1px solid #D4D4D4"
748 | :border-radius "3px"}}
749 | [:div [bp/icon {:icon "grid-view"
750 | :style {:color "#555555" {:on-click #(reset! popup-shown false)}}}
----------------------------------------------------------------------------------------------------------^
m/renderer.cljs [line 750, col 100] The map literal starting with :color on line 750 column 41 contains 3 form(s). Map literals must contain an even number of forms.
--------------------------------------------------------------------------------
751 | [:div.alert.alert-info
752 | [:div "Hello!"]]] [:br] "Color"]]]]
753 |
754 | [:div {:class "dim-c"}
--------------------------------------------------------------------------------
EDIT #2:
I realize that I part of my difficulty was that the on-click code I had copied from another source had irrelevant details. I've started over with a much simpler example.
[:div {:class "bp3-button"} [bp/icon {:icon "globe" :on-click "hello" :style {:color "#555555"}}]]
The above code compiles, but when I click the icon, nothing happens. Sorry, I know this is a terrible way to get help with a question, but super new to Clojurescript and feeling my way through the darkness.
It's a bit hard without seeing the actual compilation error, or what the bp namespace is for (I'm guessing it's related to Bootstrap?), but if you fix the indentation a bit, I think it's the following:
You have this
[:div [bp/icon {:icon "grid-view"
:style {:color "#555555" {:on-click #(reset! popup-shown false)}
[:div.alert.alert-info
[:div "Hello!"]]}}] [:br] "Color"]]]]
Your [:div.alert.alert-info is misplaced as a child of :style. What I think you meant is:
[:div [bp/icon {:icon "grid-view"
:style {:color "#555555" {:on-click #(reset! popup-shown false)}}}
[:div.alert.alert-info
[:div "Hello!"]]] [:br] "Color"]]]]
Edit: Based on your output, the code probably needs to look like this instead:
[:div [bp/icon {:icon "grid-view"
:on-click #(reset! popup-shown false)
:style {:color "#555555"}}
[:div.alert.alert-info
[:div "Hello!"]]] [:br] "Color"]]]]
This won't solve your original question, but I went ahead and created a small demo project in this repo that renders a couple of buttons, one just prints on the console and the second shows an example dialog, just like in the screenshot below:
It should work with yarn install ; yarn run html ; yarn run watch.

How to pass link options to the PhoenixHTML link with this setup

I'm currently doing a partial template for any table with search fields. I need to generate passed from controller function names with options as links in my template.
I have already tried solution I pasted as code below. It doesn't work and I have no clue why.
Controller:
#table_links [{:show, []}, {:edit, []}, {:delete, [method: :delete, data: [confirmation: "Are you sure?"]]}]
This module attribute is assigned to conn and passed to the template.
Rendering partial:
<%= render BaseAppWeb.SharedView, "table_partial.html",
Map.merge(assigns,
%{action: Routes.admin_users_path(#conn, :index),
opts: [method: :get],
columns: #searchable_columns,
table_links: #table_links,
links_path: &Routes.admin_users_path/3}) %>
Partial links generation:
<%= for {function, options} <- #table_links do %>
<%= case function do
:show -> {:safe, "<i class = \"mdi mdi-magnify\">"}
:edit -> {:safe, "<i class = \"mdi mdi-pencil\">"}
:delete -> {:safe, "<i class = \"mdi mdi mdi-trash-can-outline\">"}
_ -> {:safe, "<i class = \" mdi mdi-arrow-right-bold-circle-outline\">"}
end%>
<%= link(Atom.to_string(function) |> String.capitalize(), to: #links_path.(#conn, function, entity), options) %>
<% end %>
Error that is showing up:
lib/base_app_web/templates/shared/table_partial.html.eex:42: syntax error before: options
Without including options, as shown below, everything works fine, but I haven't got method: as link option, which is necessary in my case.
<%= link(Atom.to_string(function) |> String.capitalize(), to: #links_path.(#conn, function, entity)) %>
I'll really be grateful for any advice that will help me pass link options from controller to links in templates!
Edit:
Here is a table_partial.html.eex which you asked for:
<div class = "col-12">
<%= form_for #conn, #action, #opts, fn f -> %>
<%= Enum.reduce #columns, [], fn {function, {key, value}}, acc -> %>
<%= case function do
:date_input -> [acc] ++ [
build_form(f, {:label, {:from_date, "#{value} from"}}),
build_form(f, {function, {:from_date, value}}),
build_form(f, {:label, {:from_date, "#{value} to"}}),
build_form(f, {function, {:to_date, value}})]
_other -> [acc] ++ [build_form(f, {:label, {key, value}}), build_form(f, {function, {key, value}})]
end %>
<% end %>
<%= submit "Search", name: "order_by", value: "" %>
<hr>
<div class = "row">
<div class = "col-12">
<table class = "table dt-responsive nowrap talbe-borderless table-hover">
<thead class = "thead-light">
<tr>
<%= for {_function, {_key, value}} <- #searchable_columns do %>
<th><%= submit "#{value}", name: "order_by", value: "#{value}" %> </th>
<% end %>
<th>Options</th>
</tr>
</thead>
<% end %>
<tbody>
<%= for entity <- #entities do %>
<tr>
<%= for {_function, {key, _value}} <- #searchable_columns do %>
<td><%= Map.get(entity, key) %></td>
<% end %>
<td>
<%= for {function, options} <- #table_links do %>
<%= case function do
:show -> {:safe, "<i class = \"mdi mdi-magnify\">"}
:edit -> {:safe, "<i class = \"mdi mdi-pencil\">"}
:delete -> {:safe, "<i class = \"mdi mdi mdi-trash-can-outline\">"}
_ -> {:safe, "<i class = \" mdi mdi-arrow-right-bold-circle-outline\">"}
end%>
<%= link(Atom.to_string(function) |> String.capitalize(), to: #links_path.(#conn, function, entity), options) %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
I can't build them normally, because I'm building multiple different tables with this template and different tables Options may vary.
Ok, if someone will look for something like this in the future - here is solution I just found to pass arguments:
Controller:
#table_links [{:show, %{:method => :get, :data => []}}, {:edit, %{:method => :get, :data => []}}, {:delete, %{:method => :delete, :data => [confirm: "Are you sure?"]}}]
table_partial.html.eex
<td>
<%= for {function, %{:method => method, :data => data}} <- #table_links do %>
<%= case function do
:show -> {:safe, "<i class = \"mdi mdi-magnify\">"}
:edit -> {:safe, "<i class = \"mdi mdi-pencil\">"}
:delete -> {:safe, "<i class = \"mdi mdi mdi-trash-can-outline\">"}
_ -> {:safe, "<i class = \" mdi mdi-arrow-right-bold-circle-outline\">"}
end%>
<%= link(Atom.to_string(function) |> String.capitalize(), to: #links_path.(#conn, function, entity), method: method, data: data) %>
<% end %>
</td>
That was pretty easy, however confirmation still does not work. It was because it is confirm:, not confirmation: - working good now :)
The issue is that you are trying to pass options into a keyword list. You will want to merge the lists in one of two ways. You can either do
Keyword.merge([to: #links_path.(#conn, function, entity)], options)
or
[to: #links_path.(#conn, function, entity)] ++ options
in
<%= link(Atom.to_string(function) |> String.capitalize(), to: #links_path.(#conn, function, entity), options) %>

Active Admin with join table relation

I am configuring Active Admin. Everything is running apart from a join table, which connects the magazine resource with the keyword resource. One magazine is defined by multiple keywords and a keyword can define multiple magazines.
I have two models:
### models/magazine.rb
class Magazine < ActiveRecord::Base
attr_accessible :colour, :cover_alt, :description, :number, :short, :title_id
has_and_belongs_to_many :keywords, :join_table => "magazines_keywords"
belongs_to :title, :class_name => "Keyword", :foreign_key => "title_id"
end
### models/keywords.rb
class Keyword < ActiveRecord::Base
attr_accessible :word, :description
has_and_belongs_to_many :magazines, :join_table => "magazines_keywords"
end
And a join table:
### models/magazines_keyword.rb
class MagazinesKeyword < ActiveRecord::Base
attr_accessible :magazine_id, :keyword_id
belongs_to :magazine
belongs_to :keyword
end
This setting works for the views of my rails app, and I have the index and show section of my AA magazine resource working, but the form (for new and edit) does not work:
ActiveAdmin.register Magazine do
menu :priority => 1
form do |f|
f.semantic_errors *f.object.errors.keys
f.inputs "Magazine Details" do
f.input :title_id, :label => 'Title', :as => :select, :collection => Keyword.all.map{ |u| ["#{u.word.capitalize}", u.id] }
f.inputs :magazines_keywords do
f.has_many : magazines_keywords do |s|
s.input :keyword, :as => :select, :multiple => true, :collection => MagazinesKeyword.all.map { |u| ["#{u.keyword.word.capitalize}", u.id] }
end
end
end
f.actions
end
show do
panel "Magazine Details" do
attributes_table_for magazine do
row "Keywords", :keyword do |m|
m.keywords.map { |d| d.word }.join(", ").html_safe
end
end
end
active_admin_comments
end
end
When running the app i get NoMethodError in Admin/magazines#edit
Where /active_admin/resource/edit.html.arb line #1 raises undefined method 'klass' for nil:NilClass
I can display all the keywords in the form section with:
f.input :magazines_keywords, :as => :check_boxes, :multiple => true, :collection => MagazinesKeyword.all.map{ |u| ["#{u.keyword.word.capitalize}", u.id] }
But when I try to write them it does not work. Editing the values does not work either.
Where am I missing something? How can I get this working?
****UPDATE****
After some work I got the following solution:
form do |f|
f.semantic_errors *f.object.errors.keys
f.inputs "Saft Details" do
f.input :title_id, :label => 'Title', :as => :select, :collection => Keyword.all.map{ |u| ["#{u.word.capitalize}", u.id] }
f.input :keywords, :as => :check_boxes, :input_html => {:multiple => true}
end
f.actions
end
And as suggested:
f.input :keywords, :as => :check_boxes, :input_html => {:multiple => true} do
f.has_many :keywords do |s|
s.input :keyword, :collection => Keyword.all.map { |kw| ["#{kw.word.capitalize}", kw.id] }
end
end
With both solutions I am able to write a new Magazine entry and get the association written to the join table, unfortunately it displays #<Keyword:0x10c858858> in the form and not the word. What am I missing?
ActiveAdmin is quite smart to understand what you are trying to do. So you should ignore MagazinesKeyword and go straight to Keyword model.
So you should change this:
f.has_many :magazines_keywords do |s|
s.input :keyword, :as => :select, :multiple => true, :collection => MagazinesKeyword.all.map { |u| ["#{u.keyword.word.capitalize}", u.id] }
end
with this:
f.has_many :keywords do |s|
s.input :keyword, :as => :select, :multiple => true, :collection => Keyword.all.map { |kw| ["#{kw.word.capitalize}", kw.id] }
end
Active admin will handle MagazinesKeyword by himself.

Including a manual Rails tag in my form's parameters

This question is related to this other question:
Change rails text_field form builder type
I have a JQuery Tools Range in my form, and making it work requires that the input field be of the type "date". Rails doesn't easily allow me to do this so I've used a manual tag as follows:
<% form_for #customer, :url => {:action => "update", :id => #customer} do |f| %>
...
<%= tag(:input, {:type => :range, :value => f.object.travel, :name => "travel", :min => "0", :max => "100" }) %>
...
<% end %>
This tag shows the range slider. It also displays the right value from the database. However, when I submit a change, the "travel" attribute is sent as a general attribute and not under "customer". So, my database doesn't update.
How can I rewrite the tag so it gets included as a "customer" attribute?
Try:
<%= tag(:input, {:type => :range, :value => f.object.travel, :name => "customer[travel]", :min => "0", :max => "100" }) %>