I'm a computer science tutor, with a lot of experience teaching Python and Java but without a lot of web experience. I'm now working with a high school student who has been assigned a project that he wishes to implement in HTML and JS. So this is a good chance for me to learn more about this type of application.
It's an application for taking food orders on the web and showing an illustration of your order. You choose a main dish and any custom alterations. Then you choose another course of the meal, maybe a salad and any alterations. And so on. The first page it shows you will show an empty plate. You choose a course to customize and it will take you to a page that shows options, then another page with further options, and so forth. Each time you are finished configuring an option, it will take you back to the starting page and show a picture of the meal so far on the plate (which was formerly empty).
The main part I'm unfamiliar with is handling persistent state. Although each page will have a unique structure of images (possibly a canvas) and buttons, it will have to remember the order as configured as it loads each page.
I'm wondering what a simple way of handling this is. This is a high school student with very little prior programming experience, and I'm allowed to help her, but it has to be within her grasp to understand overall.
Perhaps sessionStorage is the best bet?
Regarding possible duplication of Persist variables between page loads, my needs are a lot more complex than that question--I need to store more than a single global variable, and I may need a framework to simplify this. In particular, I'm interested in doing this a way that is simple enough for a high school student to understand so that he can implement some of it himself (at least some of it has to be his own work). I don't know if using a framework will make the job simpler (that would be good) or whether it will require more effort to understand the framework (especially relative to an inexperienced student -- not good).
Perhaps sessionStorage is the best bet?
If you want the state to be automatically expired when the browser session ends. Otherwise, use localStorage, which will persist longer than that.
It's important to remember that web storage (both sessionStorage and localStorage) only stores strings, so a common technique is to use it to store JSON that you parse on load, so you can have complex state. E.g.:
// On load
var state = JSON.parse(localStorage.getItem("state-key"));
if (!state) {
// None was stored, create some
state = {/*...default state...*/};
}
// On save
localStorage.setItem("state-key", JSON.stringify(state));
Note that this bit:
var state = JSON.parse(localStorage.getItem("state-key"));
if (!state) {
relies on the fact that getItem returns null if there is no stored data with that key, and JSON.parse coerces its argument to string. null coerces to "null" which will be parsed back into null. :-)
Another way to do it is to use ||:
var state = JSON.parse(localStorage.getItem("state-key")) || {
// default state here
};
I have a website built with Vue.js and I need to do an audit and, optionally, implement cancel functionality for this website so I'm looking for my options/best practices.
Let's say I have an Items array defined in data() so on created () I'm doing an Ajax request and pushing data into this array of items.
Now user loads this page and does his job which for me means he changed a few objects. Let's say each Item is a Customer object and it has First name, Last name, DOB and a IsActive boolean field.
I would like to give this user an option to revert specific item to the original state without reloading anything and when he hits Save I would like to know what was changed (so I can log this information)
Here are my ideas so far:
keep a copy of the original list of Items and do a diff later to see what was changed or use it to restore objects as needed
try to utilize watch() and keep track of changes. Perhaps, I can even store this information in the object itself.
leave a UI as is and on the backend (while saving or updating) re-read object from the DB and do the job there since it is the only truly secure way of doing an audit anyway.
What's the best way to track changes and/or implement both cancel and audit?
Maybe there is a Vue-way of doing this which I'm missing, because I just switched to Vue from a different framework.
Thank you! Any help appreciated!
I am currently working on a project using Symfony2 and seeking some advice on that.
I am thinking of a hybrid application in two(2) different ways a) Login Page shall use traditional form with CRF Token and let symfonty2 handle it. b) All Inner pages ( which potentially are modules ) I want them to be non AJAX, but the other activities inside that shall behave like a Single Page.
For example I have an employee module. When user clicks on that it is entirely loaded from Server ( all the templates and forms etc ) now each activity under employee module like add/update delete/view etc shall be loaded through AJAX and response to be returned in JSON i.e AngularJS.
I am currently thinking of using FOSUserBundle to return html on initial request and then based on request type Accept: application/json it will return the JSON ( remember the add/updat delete/view part? ).
My question is it a better idea to use Angular Partials (html) files or Symfony2 Twig? or would it be better to use Angular JS, but let those partials be rendered by Symfony2 twig? ( I am thinking of Forms here, would want to validate that both from client and server side )
Has any one been through similar problem, if yes then what approach was used to develop HYBRID application using AngularJS and Symfony2 or any other framework? any relevant ideas are appreciated.
I was in the same situation you are. AngularJS+Symfony2 project, REST API, login using FOSUserBundle, etc.
... And every way has pros and cons, so there is no right way, i'm just gonna say exactly what i did.
I choose AngularJS native templates, no CSRF validation, a base template built using Twig, server-side validation, use of the FOSJSRoutingBundle, and some helpers (BuiltResponse and BaseController).
Why native templates?
With the use of verbatim, we solve the variable problems, but we gonna have a more complex logic in our templates.
We also will have a less scalable application. All our forms templates are doing a request in the Symfony application, and one of the best pros of the AngularJS is load our controllers, templates, etc from a storage service, like S3, or CDN, like Cloudfront. As there is no server-side processing, our templates would load so much faster. Even with caching, Twig is slower, obviously.
And both, Twig and AngularJS templates, are really complex to manage, in my own experience. I started making them together, but was painful to manage.
What i did?
I created static templates in front-end, with the same field names, it's not really good. We need to update the templates every time we update the forms, manually. But was the best way i found. As the field names are equal, we won't have problems to ajust the model names in the Angular controllers.
And if you are creating the software as a service, you will need to do it anyway. Will you not load the form templates from the application in a mobile app, right?
Why no CSRF validation?
We don't use CSRF validation in a REST API, obviously. But, if you wanna do it, you need to make a request every time you load a form, to get the CSRF token. It's really, really bad. So, we create a CRUD, and also we need to create a "csrf-CRUD", 4 routes more. That doesn't make any sense.
What i did?
I disabled the CSRF in the forms.
Base template?!
Yep. A base template is just to load any route in our application. Here is what i'm doing:
This will help us to avoid errors when users are going directly to some Application URL if you are using html5 angularjs urls. Simple like that.
Server-side validation, why?
If we do a validation in the Angular, we need to do the same in the server-side, so we have 2 validation codes to maintain. That is painful. Every change we do in the form, we need to change the validation in the front, validation in the back and also the Angular static form. Really, really painful.
What i did?
I basically did a server-side validation using the Symfony constraints. For every request, the application validates the form and check if any error was found, if yes, it gets the first one and send it as a response.
In the AngularJS, the application checks if there is any error inside of the errors key. So, we have a proccess used in all application to do any form request. It's like that:
And the routes?
There is another problem: the routes. Put the url directly is not a reliable way. If we change anything in the url, that route is gone and the users won't like that.
To fix that, we can use the FOSJsRoutingBundle. With that library, we can put the route name directly in the Angular controller, and it will fill with the exact url of the route. It's completely integrated with the Symfony, so parameters will work very well.
Instead using the url directly, we can do it:
Routing.generate('panel_products_show', {id: $routeParams.product_id});
And voilá! We get the route url.
That will solve the biggest part of the problems you have. But there are more.
Problem 1 - Form inputs
The forms from Symfony generally have a prefix, like "publish_product", so every field has a name like [publish_product]name. Ah, how that was a problem for me.
In the Angular, publish_product is not considered a array. You need to put the single quote to do this, like ['publish_product']name. And it's really bad, we need to change every key to use this format. In AngularJS, i was doing like that:
{{ formData('[publish_product]name') }}
Absolutely stupid.
The best solution was simply remove the form prefix in the Symfony, using the createNamedBuilder method instead just createBuilder. I let the first parameter null, and yeah, we don't need to use the prefix anymore. Now, we use:
{{ formData.name }}
So much better.
Problem 2 - Routes hard do maintain
Every request can return anything, i need to repeat much code. That is really hard to maintain, so i just create some application rules, built responses, a BaseController, etc.
createNamedBuilder
createNamedBuilder is a big method. We need to do this, for every form we have:
It's simple to solve. I just created a BaseController and i'm extending every controller from it. I created a simple method that does it.
For every route, we do not need to repeat 3 lines, much better.
Responses
When my application started growing, i had a serious problem: all my responses are different. That was really hard to maintain. For every request i was doing, sometimes i was using "response", sometimes "data", the error messages were lost in the response, etc.
So, i decided to create a buildResponse, that i just need to set some parameters and i get the same result for every route, even GET routes.
response key shows me the status and the message. It can be error or success, and the message os a optional field, that can come blank. For example, a success status with the message "You created the product".
data key shows me any information i need. For example, the user added the product, and now he needs the link to see it. In the data, i put the url of the post, and i easily can get it from the AngularJS controller.
notifications is a specific key for my business logic. Every action can return a notification to the user.
It doesn't matter what keys you have. The most important thing is have a standardized response, because when your application grows, it will be really helpful.
That is a route from my controller:
Completely standardized. The Scrutinizer code quality tool says all my routes are duplicated. :D
Have a BaseController and a builtResponse will help you so much. When i started refactoring my code, each route lost about 4-10 lines.
Details: getFormError return the first error of the form. Here is my method:
public function getFormError(FormInterface $form)
{
if ($form->getErrors()->current()) {
return $form->getErrors()->current()->getMessage();
}
return 'errors.unknown';
}
... And the parameters from the buildResponse are:
1. Status. I get it from a constant in the BaseController. It can be changed, so i believe is important do not use a string value in each route.
2. The translation message. (I use a preg_match to check if it has a translation format, because getFormError already translates the error).
3. The data (array) parameter.
4. The notifications (array) parameter.
Other problem i'm gonna have
The project just have one supported language until now. When i start to work in a multilingual version, i'm gonna have another big problem: maintain 2 versions of the translations: the back-end messages and validations and the text from the front-end. That probably will be a big problem. When i get the best approach, i'll update this answer.
I took some months to get the this approach. So many code refactorings and probaly much more in the future. So i hope it help someone to do not need to do the same.
1. If i get a better way to do this, i'll update this answer.
2. I'm not good at writing english, so this answer probably will have many grammatical errors. Sorry, i'm fixing what i'm seeing.
As mentioned in this question How can I check for live updates without using setInterval/timeout?
I am aware of websockets, but im interested in maybe a more simplistic solution, could I effectively just let php update a key value pair file and have all pages update accordingly only if a value has changed?
eg. a bidding site where instead of polling for 100 or more items I only update the whole application when someone has essentially placed a bid , making it a one way flow
place bid->process form->update database->refresh all instances of said bid currently open in other windows - hence the file that will store the info and maybe two way binding setup via angular template , or will caching be a issue?
how else do I update the views but all based on the action of someone placing a bid(submitting a form)?
Any ideas as to this approach?
You should use websockets...
if you are new to socket.IO you can use some backend as a service like firebase, this should be really easy to implement.
I'm trying to allow users to vote a record up/down with Ajax. I'm using the vote_fu plugin for the voting functionality, and everything works fine without Ajax. I'm now trying to figure out the best way to implement the asynchronous functionality with unobtrusive javascript.
What I'm doing now is having two buttons, "Up" and "Down", such that when you click either one, a request is made to votes_controller and the create or update action, depending on if the user had already submitted a vote on that record before. The params submitted would be the record_id as well as the value of the vote.
With Ajax, how should I handle the case where a user enters a page to vote without having voted on the record before? Specifically, the links would go to the votes#create in the beginning, but after that first submission, the links should switch to votes#update.
Is there a standard way to take care of this? I was thinking about just adding an extra check in the "create" method such that it would act like "update" if it found a record for the user_id, voteable_id pair, but this seemed kind of clumsy and not fully RESTful.
Thanks,
Eric
There are several techniques/patterns commonly used:
1) When your erb creates the page, you can supply a parameter to the JS script that is a part of the page. The parameter will be the "voting_url" it will be either votes/new or votes/123 depending on whether a create or update operation should be used.
2) You could use a "procedure call" as opposed to a rest call. The procedure/action would be "change_vote" -- with a param of 'up' which would be either true or false. The action would create the vote record if needed, or would otherwise modify it.
3) As part of the creation process of the main record, you could always create the vote_record. That way, the voting operations would always be updates since the vote_record will always already exist.
Added
Re: comment of when is it generally "acceptable" to move away from a rest call?
Rest is a design philosophy. It solves a lot of problems but doesn't fit all situations. I'd think that your original question would be ok but ultimately it is up to you and whomever reviews your architecture. Since it is possible to "bend" your app into a rest api for this function, some might tell you to do so--to thereby gain the benefit of not violating Restfulness.
Re: your example in your comment about friend relationships:
Since it makes sense to "create a friend relationship" it'd be better, other things being equal, to express the api as a rest "friendship object/create" call. It was exactly for your friending example that rest was created. -- The old style alternative is that each api developer had to figure out a large set of procedure names.
Rest provides a more consistent, standard way of creating the names.
Note that a "change_vote" procedure would be best defined as part of the votes object: either votes/change_vote or something similar. I believe that there is a "Rails way" for urls for rest procedures that don't fit the standard rest verbs.
Another idea would be yo change the url (through a helper probably) depending if the record is a new one.
Something like:
link_to_remote "Up", :url => voting_path(#vote)
module VotesHelper
def voting_path(vote)
if vote.new_record?
new_voting_path
else
edit_voting_path(vote)
end
end
end