Redirection with play! 2 scala after a post with angularJs - angularjs

So far I used the usual method to post a form and redirect to the page I wanted to display like this :
The HTML part :
<form name="createArtistForm" method="post" action="/admin/createArtist">
Nom de l'artiste : <input type="text" name="artistName">
<input type="submit" value="Valider"/>
</form>
And the Scala part :
val artistBindingForm = Form(mapping(
"artistName" -> nonEmptyText(2)
)(Artist.formApply)(Artist.formUnapply)
)
def createArtist = Action { implicit request =>
artistBindingForm.bindFromRequest().fold(
formWithErrors => BadRequest(formWithErrors.errorsAsJson),
artist => {
artistId = Artist.saveArtist(artist)
Redirect(routes.ArtistController.artist(artistId))
}
)
}
And it worked fine, but now, the front end part of my app is managed by AngularJs so I submit the form with its http service like this :
$http.post('/admin/createArtist', {artistName : $scope.artiste.name})
The new artist is still well saved in my database, but the redirection has no effect.
What should I do in order to make the redirection work ? What am I missing ?

What I use to do in this cases is receive the result of the operation (error or success) and in case of success, redirect on the front end side with js (location = url).

Related

Using Wordpress contact form 7 with react

I'm using WordPress as a rest API for my site, meaning the frontend is purely react. But to fetch data and stuff, I'm using WordPress backend. Now I would like to implement contact form 7 with my react app but not too sure how I can achieve this, I have looked at a solution on SO but I'm still stuck.
In my app,
I'm doing an axios post request:
const handleSend = ()=> {
axios.post('https://0xsociety.com/wp-json/contact-form-7/v1/contact-forms/258/feedback')
}
Where exactly do I put the options (email, name and message)?
This is how my contact form 7 looks like: (default)
<label> Your name
[text* your-name] </label>
<label> Your email
[email* your-email] </label>
<label> Subject
[text* your-subject] </label>
<label> Your message (optional)
[textarea your-message] </label>
[submit "Submit"]
This one:
Using Contact Form 7 with React
Here are the errors i get:
into: "span.wpcf7-form-control-wrap.your-name"
message: "The field is required."
idref: null
error_id: "-ve-your-name"
into: "span.wpcf7-form-control-wrap.your-email"
message: "The field is required."
idref: null
error_id: "-ve-your-email"
As #jules-coles correctly points out in his answer, the best way to solve this is to create your own end-point to load the form on your page.
The form is stored as HTML in the meta-field of the form post under the meta-key _form, however you will need to parse the form through the WPCF7_Contact_Form class functionalty to get convert the form tags into HTML inputs,
//retrieve your form you want to parse (form post ID)
if(function_exists('wpcf7_contact_form') ){//provided by CF7 plugin.
$form = wpcf7_contact_form($post_id); //loads the form
$html_form = $form->form_html($attr); //outputs form as html.
//$attr is an array of name=>value attributes found in the cf7 shortcode.
//you can now return you html for your rest request:
return $html_form;
}

Spring Boot: endpoints getting triggered by OPTIONS requests

I'm developing an application with React in front-end end Spring Boot in back-end.
To make http requests I'm using Axios.
GET requests work fine, however, I'm having trouble with DELETE and POST methods. It seems that they are being triggered twice: one time by the preflight request and once more by the actual request.
My Javascript code:
deletePoll = () =>{
axios.delete("anyurl/api/poll/delete",{
params : {
time_stamp : this.props.timestamp,
channel_id : this.props.channelId
}
}).then(() => (console.log("success"))
);
};
Here's where delete function is being triggered:
<div className="row align-content-center">
<Button className="delete-poll-button" variant="primary" onClick={this.deletePoll}>
Delete poll
</Button>
</div>
The whole React component:
class DeletePollModal extends React.Component{
constructor(props){
super(props);
this.deletePoll = this.deletePoll.bind(this);
}
deletePoll = () =>{
axios.delete("anyurl/api/poll/delete",{
params : {
time_stamp : this.props.timestamp,
channel_id : this.props.channelId
}
}).then(() => (console.log("success"))
);
};
render(){
return (
<Modal className="delete-modal" show={this.props.show} onHide={this.props.onHide} size="lg" centered>
<Modal.Header closeButton>
<Modal.Title>Do you really want to delete this poll?</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4 className="modal-heading">All poll data will be lost forever</h4>
<div className="row align-content-center">
<Button className="delete-poll-button" variant="primary" onClick={this.deletePoll}>
Delete poll
</Button>
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" onClick={this.props.onHide}>
Cancel
</Button>
</Modal.Footer>
</Modal>
);
}
}
And Spring Boot function:
#DeleteMapping(value = "/delete")
#ResponseStatus(HttpStatus.OK)
public void deletePollById(#RequestParam String time_stamp, #RequestParam String channel_id)
{
System.out.println("It's happening");
pollService.deletePollById(time_stamp, channel_id);
}
As you can see from the images, only one delete request is sent and the function is called 2 times
Also, if I send a POST request using Postman, everything works fine, sending an OPTIONS request does not trigger the function. However, with Axios, deleteByPollId gets called 2 times.
Why is this happening and how can I fix this problem so that the function only gets called one time?
Edit:
Looks like the problem is with the back-end.
The endpoint is being triggered, indeed, by the OPTIONS request. I've managed to achieve the same behaviour with Postman by adding
'Access-Control-Request-Method' : 'DELETE' header.
What is extremely weird, I found a temporary fix:
#DeleteMapping(value = "/delete", consumes = {MediaType.APPLICATION_JSON_VALUE,MediaType.APPLICATION_XML_VALUE})
public ResponseEntity mockDelete(#RequestHeader("Access-Control-Request-Method") String accessControl){
System.out.println("Second delete method");
return ResponseEntity.ok().build();
}
Adding this method below the deletePollById method fixed the problem. However, it doesn't even get triggered.
Can anyone explain why the back-end application is behaving this way?
You might have some problems in your component Life cycle hooks, post complete component to know about the exact problem.
If you do a DELETE or POST you don't have to worry about the OPTIONS request. It is normal and the endpoint will be called just once.
n fact, OPTIONS are most of the time informative requests launched by the browser.
It is linked with the Access-Control-Allow methods and it can be used to have a self-documented rest api.
Wikipedia says :
Returns the HTTP methods that the server supports for the specified URL.
This can be used to check the functionality of a web server by requesting '*' instead of a specific resource.
You can find some info here : w3
And here too : link
So, your server needs to indicate to the browser that the request it tries to do is allowed by setting the Access-Control-Allow methods

Form submit with Post method not working with target _blank in PWA

<form
action="some url"
method="POST"
target="_blank"
>
{_.map(somedata, (value, key: string) => (
<input name={key} key={key} type="hidden" value={value}/>
))}
</form>
I am working with a page which submits a form on click of some button, this posts some data and opens a page in a new tab. This works perfectly fine in chrome mobile android but does not work(the new url opens in the new tab but shows no data posted by the form) when i create a PWA shortcut using Add to Home Screen feature and submit the form from inside of it. Also the new tab opens inside PWA only instead of mobile android chrome.
I apologise that this relates to Jquery (it uses core JS at its heart) but I believe this is something similar to solve the form posting issue. It uses the JS FormData object which allows for files as well.
function formPost(form){
var formData = new FormData();
$(form).find('input,select,textarea').each(function(){
if ($(this).attr('type') == 'file'){
use = $(this).get(0).files[0];
} else {
use = $(this).val();
}
formData.append($(this).attr('name'),use);
})
var request = new XMLHttpRequest();
request.open('POST',$(form).attr('action'));
request.send(formData);
}
Its worth saying that for browsers this requires at least IE10 but I think at end of 2019 we shouldn't be worrying about that !! https://caniuse.com/#search=formdata (PWAs operate in "modern browsers").

Satellizer OAuth Unlinking gives 404 error

I'm testing satellizer example with Laravel back end for Facebook, once user links the Facebook account to the app its impossible to unlink it with satellizer, whenever user clicks Facebook Unilink button it gives 404 error,
http://localhost:8000/auth/unlink
404 Not found.
But on Laravel router.
Route::get('auth/unlink/{provider}', ['middleware' => 'auth', 'uses' => 'AuthController#unlink']);
Please help me to fix this bug.
Did you find the solution for this?
After check the below link I end up founding a solution for my issue.
https://github.com/sahat/satellizer/issues/269
Basically in the Satellizer documentation explain that provider and httpOptions was the parameters you can send via the unlink call, however, the options never gets passed as it only retrieves the information from the first parameter which is the provider.
You can see a bit more about the accepted parameters in the piece of code below that is inside of the satellizer.js file.
OAuth.prototype.unlink = function (provider, httpOptions) {
if (httpOptions === void 0) { httpOptions = {}; }
httpOptions.url = httpOptions.url ? httpOptions.url : joinUrl(this.SatellizerConfig.baseUrl, this.SatellizerConfig.unlinkUrl);
httpOptions.data = { provider: provider } || httpOptions.data;
httpOptions.method = httpOptions.method || 'POST';
httpOptions.withCredentials = httpOptions.withCredentials || this.SatellizerConfig.withCredentials;
return this.$http(httpOptions);
};
My not so elegant solution is as below:
html
<button class="btn btn-sm btn-danger float-left" ng-if="user.facebook"
ng-click="unlink({provider:'facebook', options: {'param1':'value','param2':'value2'}})"><i class="ion-social-facebook"></i> Unlink Facebook Account
</button>
I have basically wrapped the information I want to send by the variable provider (renamed to just data) in the JS code below.
//unlink a social login profile from user's profile
$scope.unlink = function (data) {
console.log(data);
$auth.unlink(data)
.then(function () {
toastr.info('You have unlinked a ' + data.provider + ' account');
$scope.getProfile();
})
.catch(function (response) {
toastr.error(response.data ? response.data.message : 'Could not unlink ' + data.provider + ' account', response.status);
});
The JSON sent via view does not look pretty but works:
provider Object
provider "facebook"
options Object
flag "unlink"
view "profile"
userId 236
Nothing of the above resolved the 404 issue but resolve the passing of parameters from the original satellizer unlink function.
The issue with the route happens because Laravel is blocking that route in the file Authenticate.php inside of the function "public function handle($request, Closure $next)"
You can ether route without the middware like this
Route::post('auth/unlink', 'AuthController#unlink');
Route::get('auth/unlink', 'AuthController#unlink');
Route::any('auth/unlink', 'AuthController#unlink');
The above will make sure the call will hit the controller one whay or another. how you are getting the parameters in the controller will depend if you choose post/get/any. Meaning you will retrieve the parameters via Laravel variable $request from
public function unlink(Request $request)
or using the Input facade like this
$input = Input::all();
in here you can do whatever you want with the variable values passed. Now is up to you on the handling.
Note: The satellizer code sets by default the method to POST if no method is passed in the httpOptions as you can see below:
OAuth.prototype.unlink = function (provider, httpOptions) {
if (httpOptions === void 0) { httpOptions = {}; }
httpOptions.url = httpOptions.url ? httpOptions.url : joinUrl(this.SatellizerConfig.baseUrl, this.SatellizerConfig.unlinkUrl);
httpOptions.data = { provider: provider } || httpOptions.data;
httpOptions.method = httpOptions.method || 'POST';
httpOptions.withCredentials = httpOptions.withCredentials || this.SatellizerConfig.withCredentials;
return this.$http(httpOptions);
};
That does not really helps when the code with the Laravel example comes with the route calling the get method not the post and in the js example no options of http is set to get. Meaning you are trying to call get where post is the default therefore the route will never work.
Sorry if I am not more clear as this is my first time trying to put my thinking here and English is not really my first language.
Good luck.

generate pdf with dynamic content using scala and play framework

I have a list of sessions when clicking on a session I get it and send the id to my method using angularJs:
def getSession(idSession: UUID) = Action.async(parse.json) { request =>
sessionService.findById(idSession).map {
case Some(session) =>
Ok(views.html.result.printPdf(session))
case None => NotFound(Json.toJson("Not found"))
}
}
My method works fine but it don't redirect to the view "prindpdf" also how can I call my second function which generate the pdf and take the session as parameter here is my second function:
def homepage: Action[AnyContent] = Action { implicit request =>
Ok(new PdfGenerator().toBytes(views.html.result.printPdf("Your PDF is generated"), "http://localhost:9000")).as("application/pdf")
}
and this is my view:
#(message: models.Session)
#mainPdf("Welcome") {
Image: <img src="/public/images/favicon.png"/><br/>
Hello world! <br/>
#message
}

Resources