How to dynamically change the "title" of "app", based on login info (i.e. after login succeeds or logout)? - admin-on-rest

I have this code, please see the title prop:
const App = () => (
<Admin
theme={theme}
customRoutes={customRoutes}
menu={Menu}
dataProvider={loopbackRestClient(window.apiUrl)}
authProvider={authClient()}
dashboard={Dashboard}
locale="en"
i18nProvider={i18nProvider}
title={`Dashboard - ${window.accountData ? window.accountData.accommodation.name : ''}`}
>
// more code here...
This tries to change the rendered title when login succeeds and therefore we get different accommodation.name value from there.
I was expecting that the component may re-render with this event, since login affects the REDUX state, so the window variable (which changed after login) should render a different title.
It did not work.
How may we do it the proper way (react-redux way)?

You can make a custom and connected Title component and pass it as the title prop.
https://codesandbox.io/s/1072ry6rl7
Note that my custom Title component has to support a className prop. This is a material-ui requirement.

You should save that accountData you currently have on the window object in the Redux store in its own Reducer. And when your LOGIN Action is fired I would update that accountData with the new data.

Related

MUIInputLabel does not grow when TextField is empty

The TextFields in the Material-UI docs has the label which grows and shrinks depending on whether there's a value in the field.
Rather than a user input, I am trying to use JS to reset my TextField to "" when a button is pressed. This means if a user has keyed data into the TextField, if they press the reset button, the field is cleared while the label grows to refill the field.
What is happening is that while my data is cleared, the label remains small.
Where am I going wrong with this?
I've read that it's related to something called shrink, but I dont understand how its called.
A portion of my code, built using Material-UI and ReactJS
EntryField component
<TextField onChange={inputChangedHandler} label={props.label} value={props.value} type={props.type} required={props.required} name={props.name} id={props.id} inputRef={props.propsRef} />
Form component, which uses the EntryField component above, as well as the ReactJS
const refNumRef = useRef();
const [objRefNum, setRefNum] = useState();
(...)
function resetData(event){
setRefNum('')
}
(...)
<EntryField label="Ref Number" type="text" editData={setRefNum} value={objRefNum}
id="input_refNum" name="refNum" propsRef={propRefNumRef} />
So....after posting my question, I made more trial and errors and I somehow managed to get it to work; Im not sure why.
But the main change I made was setting a default to the useState like so
const [objRefNum, setRefNum] = useState("");
And somehow this managed to fix not just this issue with the TextField, but an issue Ive been having with a Select statement as well, where I had trouble resetting it to a default value.
I will eventually have to figure out how to declare this programmatically based on API calls where the default value will change based on the results........but this is fine for now.

Page loading and state dependency between different components

I am building an application using React-Redux + React Router.
So, if user enters https://my-website.com/teams, I want to present him Teams page.
Lets suppose that my app consists of 2 components: Header and TeamsScreen.
I need to load user data to display Header.
I need to load user data & teams data to display TeamsScreen.
What is the right way to achieve it according to Best Practices?
What I have done so far:
1) Introduced a new component, lets name it AuthenticatedUser
render() {
if(!this.props.userData)
return (
<Loader/>
);
return (
<div>
<Header userData={this.props.userData}/>
<TeamsScreen userData={this.props.userData}/>
</div>
);
}
Which loads user data on componentDidMount.
If user data is null, it displays loader. If it's not null, it renders Header and TeamsScreen.
2) I give user data as property to Header. I give user data as property to TeamsScreen.
3) On componentDidMount in TeamsScreen I load teams data.
If teams data is null, I display loader for TeamsScreen. Otherwise I display TeamsScreen.
It seems working, but...In case of slow internet and/or slow database here is how it looks like:
1) There is a big loader for whole page while user data gets loaded.
2) As soon as it gets loaded, I display a header and loader gets moved a bit down till teams data is loaded and I can display TeamsScreen.
I have an uncomfortable feeling that I am doing something wrong.
Please correct me.
Thank you in advance!
Any hints / links to articles will be appreciated.
In this case you should use redux. All code related to fetch data from server will be in actions which which can first start spinner and in turn dispatch another action which will hide spinner and set your data once data returned from server.

How do you place default message in the semantic react ui search?

https://react.semantic-ui.com/modules/search
Below is images of how the semantic react ui search widget looks like. In the second image, I was wondering how you can put a prompt message to indicate to the user a message on what the search bar is meant for. In this case, it's "search". When the user types in, it erases the Search and starts reflecting what the user is typing. I thought it would be defaultValue, but it seems that you can't have value and defaultValue set at the same time. I still want to be able to read what the set value is when the user types into the box.
Thanks,
Derek
You can use defaultValue as initial value in component, no problem.
Then read the user input value in event (onBlur for instance) like this:
onBlur(e) {
e.preventDefault();
console.log(e.target.name, e.target.value);
}
If you want to read value each new character pressed you can use in onSearchChange event:
onSearchChange(e) {
e.preventDefault();
console.log(e.target.name, e.target.value);
}
EDIT: included accepted answer in comment below:
Worked:
placeholder={"text"}
for Semantic React UI Search

Calculation from Value-List in Archer GRC based on date (with non-empty validation)

I've been trying to implement what's been asked in this Stack Overflow question, here:
Calculation for status in Archer GRC based on date
Trying to create a status field based on a number of Value Lists that
users select from, but a request has been made that we check a date
field for a value to ensure an estimated date has been set so that the
calculation can determine if the status of the record is "In
Progress", "Late" or "Not Started".
...and now, I have a requirement for an actual popup warning message of some sort to prompt the user to make sure the date field is not blank.
How would I add this functionality?
In order to deliver the functionality you are looking for you have to use a "Custom Object". It is an object you put on the layout of the application in Archer that contains JavaScript code. This code will be executed as soon as the form of the application is loaded. There is a special type of the field "Custom Object" available in the Layout editor for each application in the Application Builder in Archer.
Note - I don't recommend to use custom objects in general and neither RSA Support. Every time you modify the layout in the given application, you have retest and sometimes correct IDs for your custom object. You can write an ID independent custom object and use field names, but in this case custom object will have more code. I prefer to make custom objects as short as possible.
Your custom object should do the following:
Override the behavior of the "Save" and "Apply" button in the top tool bar available for every application form in Archer.
Once "Save" and "Apply" buttons are "overwritten", every time they are clicked on your function will be called. So you need to create a click handler function.
Your click handler function will check values user is required to populate and will either return warning, or will call the original handler for "Save/Apply" buttons.
This is a code template you can start with:
<script type="text/javascript">
// ids are used to locate buttons
var buttons_ids = [
"master_btnSave", // "Save" button ID
"master_btnApply" // "Apply" button ID
];
// parameters are used in the "onclick" default handlers to call original handlers
var buttons_parameters = [
"master$btnSave", // "Save" parameter
"master$btnApply" // "Apply" parameter
];
document.getElementById(buttons_ids[0]).onclick = function(){ Validator_of_required_fields(buttons_parameters[0])};
document.getElementById(buttons_ids[1]).onclick = function(){ Validator_of_required_fields(buttons_parameters[1])};
// end of the script body
//==== Validator function attached to Save and Apply buttons
function Validator_of_required_fields(parameter){
// ids of the input fields to validate
var inputs_to_validate_ip_address = [ "master_DefaultContent_rts_XXX_YYY_t" ];
// jQuery selector is used here. Archer v5.x has jQuery library loaded by default
// you will need to modify this selector
var field_value = $('#'+inputs_to_validate_ip_address[0]+':first').val();
if(field_value.length = 0) {
// Here you are calling Archer Warning function
var msg = "[Text to display to user]";
var title = 'Required Field';
WarningAlert(msg,title);
return false;
};
// default onclick processor
ShowAnimationAndPostback(parameter);
return false;
};
Some comments on this code:
You will need to modify the validation function to work with values stored in the fields you need.
I used a rather 'unusual' way to override the behavior of the "Save" and "Apply" buttons using the following code:
document.getElementById(buttons_ids[0]).onclick = function(){ bla, bla, bla }There are simpler way to do the same, but this way custom object works fine in IE8-11, FF, Chrome and Opera. Let me know if you find a simpler way to override buttons that is browser agnostic.
Function WarningAlert(msg,title); is a build-in Archer warning message function. It worked fine in Archer v5.4. You might need to use simple JavaScript Alert function if WarningAlert doesn't work in your version of Archer.
Note that behavior of the "Save" and "Apply" buttons might be overwritten back to default in case if user opens up any pop-up dialog windows to populate a value list or cross-reference field. If that is the case, you will have to wrap the code provided into another function and attach it to the OnLoadWindow event (or similar).
I try to avoid using any JavaScript libraries in my custom objects. This way it is simpler to support them and you have less dependencies. I used jQuery in the provided example only because Archer already uses this library once the page is loaded.
Flak, make sure to test your custom object very well and good luck!

wicket: how to update a form component with ajax, not the whole form

I've got a wicket dropdown choice, and when I select something, I want to update some components within the form. This is working fine using wicket (1.4) ajax. However, it's updating the whole form including the dropdownchoice itself. There are quite a lot of items in the dropdown list (maybe 2000) so it's not great from a performance point of view.
Here's the page hierarchy:
form (Form)
|----packageDDC (DropDownChoice)
|----pptview (RefreshingView)
|----buy (Button)
packageDDC.add(new AjaxFormComponentUpdatingBehavior("onchange") {
protected void onUpdate(AjaxRequestTarget target) {
//--snip-- update pricepoints which back up the pptview
target.addComponent(form); //ie the form
}
}
In the ajax debug window I can see all the dropdown choice options being re-sent every time
What I want to do is only update the pptview and the Button via ajax, not the contents of the dropdownchoice.
I tried adding pptview to the target, but it complains that RefreshgViews can't be updated via ajax.
I tried wrapping the pptview with an EnclosureContainer, but wicket didn't like that either (something about setRenderBodyOnly)
So I tried using an WebMarkupContainer (called 'pptcontainer') and setting pptview to be a child of that - but now the pptview is not updated. Instead it says (in Ajax debug):
"ERROR: Wicket.Ajax.Call.processComponent: Component with id [[purchaseButton2f]] was not found while trying to perform markup update. Make sure you called component.setOutputMarkupId(true) on the component whose markup you are trying to update."
"ERROR: Wicket.Ajax.Call.processComponent: Component with id [[pptcontainer2e]] was not found while trying to perform markup update. Make sure you called component.setOutputMarkupId(true) on the component whose markup you are trying to update."
well these objects definitely do have this set to true:
buy.setOutputMarkupId(true);
pptcontainer.setOutputMarkupId(true);
pptcontainer.setOutputMarkupPlaceholderTag(true);
So the page is not updated correctly.
What am I doing wrong?
The new hierarchy is:
form (Form)
|----packageDDC (DropDownChoice)
|----pptcontainer (WebMarkupContainer)
| |----pptview (RefreshingView)
|----buy (Button)
I faced same problem with popup window which content is provided by ajax call. In my case the problem was solved by changing html placeholder "wicket:container" to "div" element as proposed in this article: http://sha.nnoncarey.com/blog/archives/36
After this change generated html has correct id and wicket do not have problem to find it and replace content with AJAX response.

Resources