I have a series of pages that an end user must fill out (check boxes) and when they are finished with each page I attempt to create a List of the check boxes they selected. At the end of the series of pages, I would like to show them everything that they have selected in a confirmation page. I have noticed that between requests the information in the List<> I create on each page is not available to the final confirmation page. I've tried a few different solutions (private globals) to no avail. How would I pass data across ActionResults to accomplish displaying all the selected data on the confirmation page? Thanks.
One potential solution. Others?
The web is stateless, meaning you have to store things if you want to keep them around for later use. That's true for any web framework. You'll need to store each page's results somewhere.
Options for building a wizard:
Store all of the selected answers in session and keep building it up from page to page. The final confirmation would get the results from session.
Store them in a database.
Store results in in a cookie.
Store them in HTML5 local storage
Carry them through on each page with hidden fields. Page 2 would have Page 1's answers in hidden fields, etc.
You need to save a state between the requests. You can do this with:
Query string parameters
Session state
Hidden fields
Db (if you wanna persist the intermediate choices after each request)
Local storage
Cookies
Anything else?
I'd guess, as RyanW points out, that storing them in session state is the usual way to do it. You could however fetch all steps in one request, do some fancy JS / store the intermediary results locally and make a final post when the questionnaire is complete.
Related
WARNING: This question is specific to react-admin framework
I'm trying to do an in app manual, that uses data from server to load content pages. To doing so I'm doing a custom page that fetches manual pages on componentDidMount. In this function I call react-admin crudGetList(resourceName, pagination, sortingById, filters), where filters is {and:[{condition},{language: currentLanguage}]} since I want to have the manual in different languages. I noticed that having pages in different languages in database and using crudGetList action with filters fetches the correct instances, however the state maintains old data. For example if I initially fetch data in English language, change language and go back to manual page, redux state will have pages for both languages instead of the current selected one.
Is this expected behaviour? Making the new request for manual pages shouldn't replace redux-state data to data coming from request? If is not expected should I open an issue?
React-admin uses a pattern called optimistic rendering. That means that if the app has fetched some entities in the past, if it needs to display these entities, it first shows the stale entities, then fetches the backend, and if the response differs, re-render the screen with up to date data.
For instance, when a user fetches a list of posts, react-admin stores these posts in a dictionary indexed by id:
{
123: { id: 123, title: "hello" },
456: { id: 456, title: "world" },
...
}
React-admin also stores the list of identifiers that the list should display:
[123, 456, ...]
Using these two properties, react-admin can now display the list. But it can also display the detail of a post without hitting the server first. So when a user clicks on an item in the list, react-admin uses the data from the first structure to display it right away, without waiting for the server response.
The purpose of optimistic rendering is performance: since the user doesn't need to wait for a round trip with the server, the interface is super snappy.
In your particular case, I understand that this can cause problems, because the store contains stale data that is not in the desired language. I suggest that you create a custom saga, which reacts to the language change action, and clears the store to avoid this kind of problem.
Check the documentation for custom sagas in the react-admin site:
https://marmelab.com/react-admin/Admin.html#customsagas
You have to configure how the redux store responds to new incoming data.
More specifically, this is what a "reducer" is for; your "action" (in your case crudGetList) feeds the data into the "reducer", which is just a function with instructions to the store on how it should adjust its shape based on the new data.
Somewhere in your app there's probably a reducer that responds to your fetch action, but it's configured to just shove the new results alongside the old, rather than replace them. It's very difficult to know, however, without seeing the code describing the entire redux "cycle".
The redux docs are excellent. I'd start there and make sure you have a good understanding if the entire flow of data through redux, and then go hunting for that reducer.
https://redux.js.org/basics/reducers
I just added some functionality to my site which, when a user hovers their mouse over a link (to a 3rd party page), a preview of the link is created from the meta tags on the target page and displayed. I'm worried about the implications of hot-linking in my current implementation.
I'm now thinking of implementing some kind of server-side caching such that the first request for the preview fetches the info and image from the target page, but each subsequent request (up to some age limit) is served from a cache on my host. I'm relatively confident that I could implement something of my own, but is there an off-the-shelf solution for something like this? I'm self-taught so I'm guessing that my DIY solution would be less than optimal. Thanks.
Edit I implemented a DIY solution (see below) but I'm still open to suggestions as to how this could be accomplished efficiently.
I couldn't find any off-the-shelf solutions so I wrote one in PHP.
It accepts a URL as a HTTP GET parameter and does some error checking. If error-checking passes, it opens a JSON-encoded database from disk and parses the data into an array of Record objects that contain the info that I want. The supplied URL is used as the array key. If the key exists in the array, the cached info is returned. Otherwise, the web page is fetched, meta tags parsed, image saved locally, and cached data returned. The cached info is then inserted into the database. After the cached info is returned to the requesting page, each record is examined for its expiration date and expired records are removed. Each request for a cached record extends its expiration date. Lastly, the database is JSON-encoded and written back to disk.
I'm trying to improve this form to make it a little more user friendly.
The main area I'm trying to improve is the validation process.
Right now, the form gets filled out on index page /, and the user is re-directed by the server to a /validate page. To improve the experience, the email or phone number is shown to the user so they can see whether they entered it correctly. (though rarely, it does happen)
I'm also not sure if the user should be given the opportunity to use another form of validation.
The one problem with the setup on the server side is storing the form information between page requests.
Currently I'm using the flash(one-time sessions) to store the email or the phone number. Once the user submits the form the session is lost.
I don't like using sessions for forms, because any time you have more than one window open (not that they should be in this case) the data can start to become unpredictable
I also don't want to use the url params for storing information, as this can have sensitive information being passed back and forth, and stored in browser history.
I was thinking I could do ajax, which I try not to use on sites facing a broad audience where someone is bound to be using an old version of IE.
The data I get from the form is stored in the database. I could use the GET method to store an id in params. If I use the id (or a random unique id) I run the risk of anyone guessing these ids and having access to other website users' email address and phone numbers.
I could also use a combination of the flash and hidden inputs with the unique id, but the danger of showing personal information is still there.
I'm evaluating whether AngularJS will work as a solution for my moderately simple web application.
The aim is to cut down the amount of AJAX server requests for data as much as possible.
My actual question is simple, yet the repercussions of that request is leading to confusion.
In a nutshell: "Can Angular modify parts of JSON data received from a backend through user input and maintain state until I'm ready to return that data.
Scenario:
Grab JSON data from the server that contains a root name & associated address details for each root name. The list is rendered to screen along with an 'Edit Address' button for each item.
The user clicks 'Edit Address', Angular displays a form with the address data for the root name.
The user edits the data, clicks submit, the client sends JSON data to the server and, for arguments sake, we get a success return. The address details are modified.
This is where the meat of my question - and lack of understanding - comes to the fore.
Do I need to get the entire list of 10 items back from the server with the single modified address details, just from editing a single list item OR can I simply update that single item client side and hold state as the user returns to the list, say, to edit another item?
IOW, we get a success, but no data is actually returned aside from 'success' - our client has stored the changes.
This is where the data integrity issue rears it's ugly head.
** OR **
Grab a list of root items without associated address data.
The user clicks on an 'Edit Address' button for the root item.
We fetch the address data for the root name from the server and the form is displayed, the user edits the data, submits, send data asynchronously, get a success.
User returns to the list and another server request is made to grab the list from the server again.
This is hellishly difficult to explain, but the bottom line is about persistence and data integrity.
Is it best practice to make a server requests after each user edit of data, or can modified data be stored client side - with persistence?
obviously validation will be done server side, as well as client side.
What you're asking is more of a server-side question, on how to design a good RESTful API that allows changes to individual entities without sending/loading the entire list each time. So the answer to your question is that it's entirely up to you... angular does a great job of binding UI elements to the javascript objects in your controllers for you, but when it comes time to save that data to the server, you can do it however you want.
In an ideal world (IMO) your server-side API would support the following:
Get a list of addresses (angular stores them in $scope.addresses)
Get a single address
PUT/PATCH to update an address (when a user makes a change to a single address and confirms it) and return 204 no content
POST to create new addresses, and return the created address with a server-provided identifier (like "id"), that you can use in angular to determine whether an address has been persisted server-side or not. After POSTing, you rewrite the angular scope object with what you got from the server to save the id field.
DELETE to remove them (returning nothing)
With this, when you have the client create an address, you should send a POST to the server to create one, take the response JSON and copy it over the object you just saved, so that now it has an "id" field (or similar). You can use angular templates to visually represent that anything with an "id" field is saved to the server. This way you don't have to re-grab the whole list every time you save.
For updating addresses, this is why PATCH is useful: you can send only the changes to individual fields to the server and ensure that only things the user has changed get sent.
Deleting addresses can work by checking if the "id" field is there, and if so, send a DELETE to the server, and if not, the object was never "saved", so just remove the address from the scope. Upon successful deletion you can just remove the address from the scope, no need to reload everything.
When it comes to the "data integrity", ie. if there's other addresses created since you've done the original data request, you'll have to do this on your own... Ideally similarly to how Stack Overflow or Github does it, which is to hint in the UI that there has been server-side changes and you should click to refresh. How to determine refreshes is up to you, but you can keep it simple with polling at intervals, or you can go all out and do WebSockets/Server-side events and actually push changes to the browser.
The best way to create UIs that persist to the server is a complicated topic and there are a lot of best practices. Angular will support whatever you want, but you need coordination on the server to do it.
I am using sessions to store data from my multi step form so that when the user completes all three sections of the form then the information is inserted in to the database. I have built the form so that the user can go back to any stage and modify the information they have submitted, the thing is though, the values that repopulate the form are stored in sessions so if the user leaves the form page and goes elsewhere in the website and then returns to the form the information is still in the form…is there a better way to do this? I want the data destroyed if they leave the form…
Thanks
Assuming your form exists only in one controller and isn't spread across multiple ones, you could simply unset all session values in the __construct of every other controller. (You could extend the base controller if you have lots to save the hassle of adding this functionality to many.
That way if the user visits another section, the values will be lost, but providing they remain within the "form" they can remain intact.
You could with JavaScript and the unload event, but it'll prove tricky since unload may fire with each "section" of the form.