reagent render multiple components - clojurescript

I've got two reagent components that will display on different pages of my web application. Tested individually, they both work exactly as they ought. When I try to render both of them, only one is displayed.
Here is the clojurescript:
(defn mount-components []
(r/render [#'password-component] (.getElementById js/document "password"))
(r/render [#'test-component] (.getElementById js/document "test")))
(defn init! []
(mount-components))
On the back end I have this:
(defn password-page []
(layout/base
[:h1 "Change your password"]
[:div#password]))
(defn home-page []
(layout/base
[:h1 "Hello!"]
[:div#test]))
(defroutes app-routes
(GET "/" [] home-page)
(get "/password" [] password-page))
After I compile the clojurescript and look at the pages, only the password component displays. If I swap the order in the mount-components function, so that test-component is first, only test-component displays and not password-component.
How do I display both components at the same time?

I think the problem is possibly a type of design flaw in your implementation. In react programs, it is changes in your state atom which will trigger a re-rendering. From the provided code, it isn't clear what the 'trigger' is which will cause a re-rendering to occur. It might hlep to actually see the full page code to see how you are calling the javascript - it could simply be that init is only running with the first page load and not for every page. What could be happening is
You visit the first page. The mount-components function is called and finds only one of the div elements targets for your component, so you only see one component rendered.
You visit the second page. Now you have a page with the 2nd div element, but the problem is nothing in your local state has changed to trigger the re-rendering of components, so you don't see the second component. Basically, something needs to tell reagent/react that you need to re-render the component.
With reagent, I think it works much better if you implement the client side as a single page app (SPA). You use a reagent atom to store your app state and use the values in that atom to determine/control what/when components are rendered on the page. Calls back to the server are predominately used to just pass data back and forth rather than page html (gross simplification and overlooks things like client side rendering).
If you really want to do it the way you are, you probably need to put your render commands in different functions and then have different javascript calls in each page which will call the corresponding 'run' function which will render the component. Alternatively, you could link your components to some sort of state flag which is updated when a new page is loaded so that the mount-components function is re-run when a new page arrives.

Related

CLJS/Reagent: React does not recognize the prop on a DOM element

I see there are lots of similar question in Javascript/React but I'm having this issue with CLojureScript/Reagent and I'm at a loss about how to solve it without messing up all my app-state names.
So I'm getting these warnings in the browser console:
react_devtools_backend.js:2430 Warning: React does not recognize the `showWarning` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `showwarning` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
These appear to be coming from the name of an item in the app-state:
(defonce app-state (reagent/atom {:show-warning "none"}))
The only solution I've found is to rename the item from :show-warning to :showwarning but this leads to a bunch of hard to read items.
I don't have any real control about how Reagent renames keys like :show-warning to "showWarning" but it seems this, being basic to how React works, would have a cleaner way to handle this.
Thanks!
React really shouldn't be able to see your state or care what's in it. My guess would be that you are rendering your state somewhere in the props positions. Most likely somewhere in your code you have [:div #app-state]. Possibly you were trying to render the state and should've done [:div {} #app-state].
This is perhaps a bit of a gotcha with Reagent, since [:p #im-a-string] would render the string but [:p #im-a-map] will treat the map as props.

How do I automate tab selection on a website

Here is the website I am trying to access. I dont want the default tab (Day) though, I want to select the Season tab
https://www.eex.com/en/market-data/power/futures/uk-financial-futures#!/2017/05/23
The link appears to be exactly the same whichever tab is chose making differentiation impossible as far as I can tell.
Any help on this would be much appreciated, using whichever programming method and language is appropriate.
Kind Regards
Barry Walsh
The URL does not change since this is an ajax request, which you can see from MarketDataTableAController's getPageData function. You can read about them here https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started
Ive inspected your html and you seem to be using angular. On further inpection you can see that the tabs have ng-click="setActiveTab(tab)" attribute on them. So whenever user clicks, this function gets executed. It is a matter of using this function with the appropriate tab object to get the content to change. You for example could put setActiveTab(tab) into your controller init method since setActiveTab() calls the forementioned getPageData() function to update the page.
Also the tab you are looking for is page.tabs[5] ($parent.page.tabs[5] if referring from TabController) since this is the tab with the label of season. Pass that to setActiveTab() and it should show you the season instead.
However this might not be a good solution since the tab array ordering might change. Then you would need to loop over all objects in page.tabs and see if tab.label === "Season" and pass that in the function instead or better yet use the $filter service provided by angular which would look more cleaner.
Your code source also seems to be minimized and its not very easy to read.

Using Draft.js with Reagent

Does anyone have any luck adapting Draft.js for Reagent? There's pretty heavy editing issues if Draft.js is imported right away via reagent/adapt-react-class. Cursor jumps, disappearing symbols when you're typing, onChange calls with incorrect EditorState, you name it.
People are reporting problems like this in clojurians/reagent Slack channel, but it seems there's no solution so far.
Any help would be greatly appreciated.
Okay, thanks to tonsky, I got the answer. Reagent/Rum are using deferred rendering with requestAnimationFrame, but Draft.Editor should be re-rendered immediately when editorState is set.
All we need is to call forceUpdate for editor parent component whenever editor onChange is invoked:
:editorState #editor-state-atom
:onChange (fn [new-state]
(reset! editor-state-atom new-state)
(.forceUpdate #wrapper-state))
Code example is for Reagent, solution for Rum is identical
Just an idea (more of a comment, but I can't provide comments yet), because -- if I remember correctly -- the :content-editable attribute is treated in a special way within Reagent:
Since the problems seem to occur when the Draftjs editor is called from Reagent, would it not help to convert the Reagent-component to a React-component (using reagent/reactify-component), and then use this "reactified" component as a react-component within Reagent, using reagent/create-element? I would assume that Reagent then refrains from meddling with the Draftjs editor.

How to handle popstate when url ceased to exist?

I would like to be able to do two things with html5 popstate, I'm not using any plugins just these two methods:
Push State:
function contentLoaded(...) {
...
window.history.pushState({ pageUrl: url }, url, url);
...
}
Pop State:
$(window).bind("popstate", function (e) {
if (event.state) {
loadContent(event.state.pageUrl);
}
});
Now if I delete a record, I want to avoid popping a state which couldn't be loaded, just skip it and try popping the next one.
The second question would be: How can I avoid try popping from an empty stack (I have a back button inside my app, but I can get rid of it with an appropriate reason), but keeping clear if the content couldn't be loaded OR if there is no more items in the stack.
History is not meant to be changed afterwards. You should separate the push/popstate functionality from the content loading functionality; think the "router" or "navigator" pattern in typical client-side mvc framework. If a state has become invalid, the content loading code can "redirect" to another state (by calling pushState), just as you would do in regular server-side app.
Just to remind, a client-side application should work identically whether the state was internally popped or the page was actually loaded using the same url, i.e. the HTML5 history support must be transparent, or in other words, the url alone must contain all the information to construct a particular view (but in the case of popstate, we can cheat and reuse the existing state to speed up things).

Using a single shared element across multiple partial views

I have a basic ASP.Net MVC 3 application which has a number of controllers and a number of actions (and subsequently views)
A common feature of the application is to show a pop-up dialog window for basic user input. One of the key features of this dialog process is a faded mask that gets shown behind the dialog box.
Each of these dialog window controls is in a separate Partial View page.
Now, some view pages may use multiple dialog boxes, and therefore include multiple partial views in them - which as is would mean multiple instances of the "mask" element.
What I am trying to find a solution for is to only need to create one instance of a "mask" element regardless of the number of dialog partial views I include, and then the script in each partial dialog will have access to this element (so basically it just needs to be on the page somewhere)
The only real idea I have come up with so far is to add the "mask" element to the master page (or in the original view page) and this will mean it only gets added once. The problem here is that it will be added even when it is not needed (albeit one small single element)
I can live with this, but I would like to know if there is a better way to handle these kinds of scenarios?
A quick idea that came to mind is some kind of master page inheritance hierarchy, So I may have a DialogMasterPage that inherits from the standard current master page. How does that sound for an approach?
Thanks
To do something like this, where each module can register their need for a certain thing in the master page, you can use HttpContext to store a flag of whether you need to write the mask div, and just set that property in each partial. At the end of the master page, if the flag is set, you can then write the mask div if its set to true.
Obviously to make this cleaner you could wrap it all in an HtmlHelper extension or something.
My initial thought is for you to use something like jQuery UI where it handles the masking for you or if you are using something custom you can load the content for the dialog via ajax then show it in the single dialog on the master page.