I wonder how showing and hiding of a modal dialog should be implemented with Om or Reagent. Since my UI is a function on the state, the show/hide should be triggered by a property in this state.
But frameworks like Bootstrap require to call some JavaScript to show/hide dialogs.
Is there any common solution for this problem?
Don't use javascript or jquery effects to show/hide dialogs in Om or Reagent. Instead, make the value of an atom determine whether the modal dialog should be shown. Here is an example for Reagent:
[(fn [shown]
(if shown
[:div.jumbotron.modal-background
{:on-click #(reset! popup-shown false)}
[:div.alert.alert-info
[:div "Hello!"]]]
[:div]))
#popup-shown]
Have a look at re-com. It certainly shows one way of doing it.
https://github.com/Day8/re-com
For Bootstrap specifically, the JavaScript adds "show" to the modal's class and style="display: block;" to the modal. By adding these to the modal we can force it to display all the time, we can then use conditional rendering to hide it:
(defn my-modal []
(let [show #(app-state/query :modal-showing)]
(when show
[:div.modal.show {:tabIndex -1
:style {:display "block"}}
[:div.modal-dialog
[:div.modal-content
"etc"]]])))
Where you get your show boolean from and how it's updated will be application specific, but hopefully this is sufficient to demonstrate the idea.
Related
I'm trying to show and hide a form field using Angular's *ngIf but, when I do, the entire form doesn't render no matter the value I give the *ngIf and no errors are thrown. Clearly the *ngIf isn't the way to go. Is there a more DevExtreme way to do this? I see there is a visible in the documentation but I don't just want to hide it.
HTML
<dx-form id="companyDetailsForm" [(formData)]="company" [showColonAfterLabel]="false">
<dxi-item dataField="Name">
<dxi-validation-rule type="required" message="Name is required"></dxi-validation-rule>
</dxi-item>
<dxi-item *ngIf="hasParent" dataField="Parent" caption="Parent">
<dxo-label text="Parent"></dxo-label>
</dxi-item>
</dx-form>
Use visible property instead, *ngIf does not work in the DX Form.
<dxi-item [visible]="hasParent"
I think it has to do with how select2 creates the actual dropdown outside of the element it is based on.
Is there a way to suspend the cells "blur" activity until the user has made a selection, or in general just make the select2 more usable inside the kendo grid?
I hastily made this jsfiddle. I put the select2 inside the first column.
function testEditor(container, options) {
var customInput = $('<select name="' + options.field + '" data-text-field="text" data-value-field="id" />');
var scheduleContactSelect =
customInput
.appendTo(container)
.select2(
{
data: ["test1", "test2"]
});
}
http://jsfiddle.net/zaq3a3o5/
As you can see, the moment you start interacting with the select2, the cell closes edit mode but leaves the select2 hanging.
So it turned out the solution was three parts.
Use the "dropdownParent" select2 config option to make sure it appends the disconnected dropdown part inside the same element.
Make sure you are using Select2 4.03 or higher. (I had to upgrade to 4.03)
Define the "focusout" event while inside the "select2:open" event for the select2 search box so we can preventDefault() and stopPropagation() to prevent "focusout" from bubbling up.
I am creating a page that displays, and then edits, renter info using om-boostrap. (I know Clojure, but am new to CLJS/Om/React/modern web development in general.) The UI and functionality between displaying and editing tenant info is similar -- both can use input fields; editing just needs the fields to be "text" instead of "static" and needs "Submit" and "Cancel" buttons.
The problem I face is that I can't figure out the React/Om way to change a component like that. The view is defined as follows:
(defcomponent view [{:keys [id] :as app} owner]
(render
[_]
(let [tenant (get #tenants id)]
(dom/div
(om/build header/header-view app)
(dom/div {:class "h3"} "View Tenant\t"
(utils/button {:on-click (fn []
(om/update-state! owner
#(assoc app :edit? true))
(om/refresh! owner))}
"Edit"))
(om/build tenant-info {:edit? (:edit? app)
:tenant {:id id
:name "Funny name"
:unit-addr "Funny addr"
:rent "Lots of rent"}})))))
I won't paste the entire tenant-view function here, but it builds Bootstrap inputs for each tenant data field using om-bootstrap:
. . .
(let [input-type (if edit? "text" "static")]
(i/input {:ref "name-display"
:type input-type
:label "Tenant Name"
:label-classname "col-xs-2"
:wrapper-classname "col-xs-4"
:value (str name)})
. . .)
I've tried multiple approaches. I've posted my most recent, using the button's :on-click function to modify the app state, setting the edit? property to true and prompting a re-render to make the inputs editable.
This doesn't work and I am not finding guidance in the React or Om documentation.
What is the right way to render the same component differently? (In my case, the view function's input fields.)
What React or Om documentation is relevant?
UPDATE: I can get the inputs to be editable when I hard-code the edit? flag to true, so making the inputs editable is not the issue: the problem is toggling from static to text (and presumably vice versa).
Yes the problem has to do with understanding the difference between the app state and component state. In this case we wish to affect the app state,I don't understand your scenario quite well but I think it would be better to use component local state for this. You can use init-state or :state. and you can use om/update-state! as you wish. However just adding onto the previous answer it would be easier to just use om/update! to affect the app state in your scenario.
(utils/button {:on-click #(om/update! app [:edit?] true)}
"Edit")
is another option where you can have the vector of keywords go as deep into the map as you like.
This is more terse but might cause a JS console warning because we ignore the event from on-click.
I think the problem is you are using om/update-state! which is for transitioning component local state instead of om/transact! which is used for updating the props passed in to your component. So try changing your button component to this:
(utils/button {:on-click (fn []
(om/transact! owner #(assoc app :edit true)))}
"Edit")
I have a span with an ng-click="..." attribute. The ng-click slightly modifies the span's CSS within the DOM so that it is more button-like. Within my application I wish to toggle whether or not that span is clickable or not. I can make the ng-click not do anything easy enough but what I would prefer is to just remove/disable the attribute altogether. This is to avoid all "buttonizing" that the ng-click does to the element. It would also be nice if the attribute were re-enabled if the clickable variable becomes true again.
I would like a solution that avoids using $scope.$watches because my application is pretty large and watches are slow.
Thanks!
I think you can have two spans with and without ng-click attribute and based on that clickable variable you control those two spans with ng-if or ng-show
Simple solution suggested by to Achu!
Just use two spans rather than toggle the attribute on a single span.
<span ng-if="clickable" ng-click="...">Click me!</span>
<span ng-if="!clickable">Cant click me!</span>
If I were in such a situation, I would not try to enable or disable ng-click attribute. Rather, I would use some flag variable with the $scope to see if click function should perform its functionality or not like in your controller you have a method like
$scope.spanClick = function(){
if(!$scope.shouldClick){
return;//simply do nothing
}
//Do button click logic
}
In jQuery you can force focus onto an input using something along the lines:
$("input[name='text']").focus();
But how is it done in ClojureScript (preferable something Enfocus friendly) ?
Without using enfocus, you can do this by calling javascript functions, e.g.
(-> js/document (.querySelector "input[name='text']") (.focus))
or using .. threading:
(.. js/document (querySelector "input[name='text']") (focus))
I must have been very tired, the following works :)
(ef/at "input[name='text']" (focus))