I would like to use AJAX in my Symfony3.0.3 project.
The communication works, but I can't get variable from JS to the handler. In the direction handler to JS, it works fine.
I'm trying to get the variable from the request with "$request->query->get('id'))" but I only get "null".
In an other way I'm trying to use the variable from the URL but I get this error:
"An exception has been thrown during the rendering of a template ("Some mandatory parameters are missing ("id") to generate a URL for route "admin_ajax".") in CommonBundle:Default:index.html.twig at line 421."
I don't mind using a solution or an other (I'll use the best one depending of your advices), but I still would like the solution for both error.
JS
function selectClient(idClient)//idClient = 1
{
alert(idClient);
$.post('{{path('admin_ajax')}}',{idClient: id},
function(response)
{
if(response.code == 100 && response.success)
{
alert(response.id);//Show null if using $request->query->get('id')) in handler but should be 1
}}, "json");
}
routing:
admin_ajax:
defaults: { _controller: CommonBundle:Default:getClient }
path: /ajax/{id}
handler:
public function getClientAction($id)
{
$request = $this->container->get('request_stack')->getCurrentRequest();
$isAjax = $request->isXMLHttpRequest();
if ($isAjax)
{
$response = array("code" => 100, "success" => true, "id" => $request->query->get('id'));
return new Response(json_encode($response));
}
$response = array("code" => 0, "success" => false);
return new Response(json_encode($response));
}
EDIT:
Thank for Rim, and Rvanlaak answer, I used the FOSJsRoutingBundle.
JS
function selectClient(idClient)
{
$.get(Routing.generate('ajax_getclient', { id:idClient }),
function(response)
{
if(response.code == 100 && response.success)
{
alert(response.id);
}
else
}, "json");
}
routing:
ajax_getclient:
defaults: { _controller: CommonBundle:Default:getClient }
path: /ajax/{id}
options:
expose: true
Note that the option "expose: true" was necessary to works.
Thats because the twig is executing before javascript so he is not reconizing the client id param
i had the same problem and resolve it using FOSJSRoutingBundle see this post :
Ajax url parametetr using Twig path
Related
Don't understand why have to error in the method. What I do wrong?
I'm using Ziggy routing for js
management.site.destroy:
domain: null
methods: ["DELETE"]
uri: "management/site/{id}"
Have console error
DELETE http://localhost/blog/public/management/site 405 (Method Not Allowed)
have button and js on it
<button type="button" name="ok_button" id="ok_button" class="btn btn-danger">OK</button>
JS
$(document).on('click', '#ok_button', (function (e) {
var product_id = $(this).val();
var token = $("meta[name='csrf-token']").attr("content");
$.ajax({
url: route('management.site.destroy',product_id),
beforeSend:function(){
$('#ok_button').text('Deleting...');
},
type: 'delete',
data: {'product_id':product_id,
'_token': token,},
success: function (data) {
setTimeout(function(){
$('#confirmModal').modal('hide');
alert('Data Deleted');
location.reload();
}, 2000);
}
});
}));
Controller:
public function destroy($id)
{
$company_id = Auth::user()->company_id;
$item = Site::firstWhere(['company_id'=>$company_id,'id'=>$id]);
$item->delete();
return response()->json(['success' => 'Data is successfully Deleted']);
}
Route (Edited added full route) in patch and etc work fine
Route::group([ 'as'=>'management.','namespace' => 'Management', 'prefix' => 'management','middleware' => ['role:administrator'] ], function () {
Route::get('/', 'ManagementController#index');
Route::group(['as' => 'site.','prefix' => 'site'], function () {
Route::get('/','SiteController#index')->name('index');
Route::post('store','SiteController#store')->name('store');
Route::post('edit/{id}','SiteController#edit')->name('edit');
Route::get('edit/{id}','SiteController#edit')->name('edit');
Route::patch('','SiteController#update')->name('update');
Route::delete('{id}','SiteController#destroy')->name('destroy');
Route::get('{id}','SiteController#view')->name('view');
});
Is this:
Route::delete('{id}','SiteController#destroy')
wrapped in a Route group?
If it is not, then your delete() methods route will actually be /{id} and not management/site/{id}
In your console, run php artisan route:list to display the full list of registered routes for your application. Then check what the registered route is for your delete method.
Edit (Round 2)
So the registered route is:
| DELETE | management/site/{id} | management.site.destroy | App\Http\Controllers\Management\SiteController#destroy | web,role:administrator
This is expecting the delete request to be http://localhost/management/site/{id}
However, the error being returned indicates the path the request is making is incorrect:
DELETE http://localhost/blog/public/management/site 405 (Method Not Allowed)
It may well be that you have a relative path somewhere which is adding the /blog/public/ section of your URI!
TLDR;
http://localhost/blog/public/management/site != http://localhost/management/site/{id}
I'm setting up a Booking router in NodeJS, and I have many params in.
Now when I forgot params I return an error like :
500: Need more information
I wonder if it's possible to know which params are missing when I return the error code.
This is for a new API made in NodeJS
Here are the params that I want to retrieve from the front ( made in ReactJS )
let body = {
agentDutyCode: "STRING",
RatePlanCode: params.rateCode,
RoomCode: params.roomCode,
AmountAfterTax: params.amountTax,
Start: params.fromDate,
End: params.toDate,
CardCode: params.cardCode,
CardNumber: params.cardNumber,
ExpireDate: params.expireDate,
SeriesCode: params.cvv,
CardHolderName: params.nameCard,
ChainCode: params.chainCode,
HotelCode: params.hotelCode,
RoomQuantities: params.roomQuantities,
GuestQuantitie: params.numberGuest,
GuestPerRoom: params.guestPerRoom,
LastName: params.lastName,
FirstName: params.firstName,
PhoneNumber: params.phoneNumber,
email: params.email,
FVL_SUBUNIT_7: params.walletAddress
}
And this is my promise :
cdsJson.bookResource(req.body)
.then((response) => {
if (response !== null) {
res.response = {
...response
}
} if (response.hotel.length === 0) {
res.respStatus = 500
res.response = {
sendMsg: "Need more informations"
}
next('route')
}
return response
})
If the request succeeds I got a reservation ID otherwise I got :
Error 500: Need more information
Read the documentation or the source code.
Seriously. If the API response doesn't tell you in the error message, then there is no way to know what parameters it expects programmatically.
try it for a for ... in loop like this:
cdsJson.bookResource(req.body)
.then((response) => {
if (response !== null) {
res.response = {
...response
}
} if (response.hotel.length === 0) {
res.respStatus = 500
let errorStr = "Need more informations"
for(var key in req.body) { // Get all parameters that are not set
if(objects[key] == undefined)
errorStr += "\nParameter ["+key+"] is missing!"
}
res.response = {
sendMsg: errorStr
}
next('route')
}
return response
})
You're trying to do server side validation. In Node a good approach would be to define a JSON Schema for the expected parameters and then in your route handler validate the data sent in the request with a JSON Schema validator. This would help you work out whether a request was valid and help you generate error messages automatically. As a rule it's much better (i.e. simpler and more maintainable) to use tools that enable you to declaratively declare your validation (via a schema) than imperatively write code to manually validate objects.
JSON Schema spec https://json-schema.org/
A validator https://github.com/epoberezkin/ajv
There is a situation that I have to get extra data after my first ajax (in mounted function) in vuejs, I have put the second ajax in if condition and inside success function of the first ajax!
It is working and I see data in Vue Devtools in chrome, but data is not rendered in view.
Pseudo Code:
var vm = new Vue({
el: '#messages',
data: {
participants: [],
active_conversation: '',
messages: []
},
methods: {
getParticipants: function () {
return this.$http.post('message/get-participants').then(
function (response) {
vm.participants = response.data.participants;
// if there is a conversation_id param in url
if (getUrlParameterByName('conversation_id')) {
// Second Ajax Is Called Here inside First Ajax
return vm.getConversationMessages (getUrlParameterByName('conversation_id')); // this ajax call is getting data but not showing in view
}
}
},
getConversationMessages : function(conv_id){
// Second Ajax Call to get Conversation messages
// and showing them , works onClick
return this.$http.post('message/get-messages/' + conv_id).then(
function (response) {
if (response.data.status == 'success') {
console.log(response.data.messages)
vm.messages = response.data.messages;
vm.$forceUpdate();
}
},
mounted: function () {
this.getParticipants()
}
})
The Second Ajax Call to get a specific conversation messages is responding to onclick event and showing messages, but when this function is used inside the First Ajax success response (getParticipants()), its getting data correctly nd I can see in DevTools VueJs Extension that messages are set but view does not show messages, I have tried vm.$set() but no chance.
Update:
The second Ajax is working with no errors and messages data property get filled (I checked Vue DevTools), The only problem is that view does not show the messages!! but when I do it manually by clicking on a conversation, second ajax is executed again and I can see messages!, I also tried vm.$forceUpdate() after second ajax with no chance.
Update2 html part(the bug is here!!)
<a vbind:id="conv.id" v-on:click="getMessages(conv.id)" onclick="$('#user-messages').addClass('active')">
the DOM is updated with messages with when you do the ajax request with only getConversationMessages and not placing
getConversationMessages in the success callback of the ajax request of getParticipants is the fact that an error is encountered at this line
this.participants = response.data.participants;
you are using a normal function in the success callback of the ajax request that's the reason this does not point to the vue instance
adnd this.participants gives you an undefined error. So use vm insteaad to point to the vue instance as you did in the rest of the program
vm.participants = response.data.participants;
Edit
var vm = new Vue({
el: '#messages',
data: {
participants: [],
active_conversation: '',
messages: []
},
methods: {
getParticipants: function () {
return this.$http.post('message/get-participants');
},
getConversationMessages : function(conv_id){
return this.$http.post('message/get-messages/' + conv_id);
}
},
mounted: function () {
this.getParticipants().then(function (response){
vm.participants = response.data.participants;
if (getUrlParameterByName('conversation_id')) {
return vm.getConversationMessages (getUrlParameterByName('conversation_id')); // this ajax call is getting data but not showing in view
}
}).then(function(response){
if (response.data.status == 'success') {
console.log(response.data.messages)
vm.messages = response.data.messages;
});
}
})
Call second http request after first is completed using http callback or you can use Promise too.
return this.$http.post(function(response){
// first call
}).then(function(response){
// Second call
})
new Vue({
el: '#messages',
data: {
participants: [],
active_conversation: '',
messages: []
},
methods: {
async getParticipants (id) {
var response = await this.$http.post('message/get-participants')
this.participants = response.data.participants
if (id) this.getConversationMessages(id)
},
async getConversationMessages (id) {
var response = this.$http.post('message/get-messages/' + id)
if (response.data.status === 'success') {
console.log(response.data.messages)
this.messages = response.data.messages;
}
}
},
created () {
this.getParticipants(getUrlParameterByName('conversation_id'))
}
})
The problem for me was in html, I added a custom onclick event to the div element previously and this event was conflicting with Vuejs events.
I have the following code in my Model.js file.
Model.observe('loaded', (ctx, next) => {
const {
data,
options: {
user
}
} = ctx;
const owner = (user && data && user.uid === data.userId) || false;
console.log(
`${data.id}: loaded - access by ${user && user.name}, owner:${owner}`
);
if (!owner) {
delete data.testProp1;
}
console.log('returning: ', ctx.data);
next();
});
When I make a request, I see the following log output (server logs):
f3f9ffd6-14dc-42e5-94ba-503aa3426faa: loaded - access by User1, owner:false
returning:
{
testProp2: true,
id: 'f3f9ffd6-14dc-42e5-94ba-503aa3426faa',
userId: 'sfeywkKSuBTlf0DwE4ZOFd8RX5E3'
}
But then in the actual response the browser receives I actually get:
{
testProp1: true,
testProp2: true,
id: 'f3f9ffd6-14dc-42e5-94ba-503aa3426faa',
userId: 'sfeywkKSuBTlf0DwE4ZOFd8RX5E3'
}
Is there something in the documentation I am missing? Deleting the property is exactly what it shows in the Loopback docs here. Also, I actually see the modified data as the data property on the ctx object before calling next(). Anyone run into this issue or know some caveat to the docs that isn't explicitly stated?
I'm looking for a way to determine if Meteor.user() is set in a function that can be called both from the server and client side, without raising an error when it is not.
In my specific case I use Meteor server's startup function to create some dummy data if none is set. Furthermore I use the Collection2-package's autoValue -functions to create some default attributes based on the currently logged in user's profile, if they are available.
So I have this in server-only code:
Meteor.startup(function() {
if (Tags.find().fetch().length === 0) {
Tags.insert({name: "Default tag"});
}
});
And in Tags-collection's schema:
creatorName: {
type: String,
optional: true,
autoValue: function() {
if (Meteor.user() && Meteor.user().profile.name)
return Meteor.user().profile.name;
return undefined;
}
}
Now when starting the server, if no tags exist, an error is thrown: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.
So in other words calling Meteor.user() on the server startup throws an error instead of returning undefined or null or something. Is there a way to determine whether it will do so prior to calling it?
I cannot solve this simply by wrapping the call with if (Meteor.isServer) within the autoValue function, as the autoValue functions are normally called from server side even when invoked by the user, and in these cases everything in my code works fine.
Note that this is related to How to get Meteor.user() to return on the server side?, but that does not address checking if Meteor.user() is available in cases where calling it might or might not result in an error.
On the server, Meteor.users can only be invoked within the context of a method. So it makes sense that it won't work in Meteor.startup. The warning message is, unfortunately, not very helpful. You have two options:
try/catch
You can modify your autoValue to catch the error if it's called from the wrong context:
autoValue: function() {
try {
var name = Meteor.user().profile.name;
return name;
} catch (_error) {
return undefined;
}
}
I suppose this makes sense if undefined is an acceptable name in your dummy data.
Skip generating automatic values
Because you know this autoValue will always fail (and even if it didn't, it won't add a useful value), you could skip generating automatic values for those inserts. If you need a real name for the creator, you could pick a random value from your existing database (assuming you had already populated some users).
Been stuck with this for two days, this is what finally got mine working:
Solution: Use a server-side session to get the userId to prevent
"Meteor.userId can only be invoked in method calls. Use this.userId in publish functions."
error since using this.userId returns null.
lib/schemas/schema_doc.js
//automatically appended to other schemas to prevent repetition
Schemas.Doc = new SimpleSchema({
createdBy: {
type: String,
autoValue: function () {
var userId = '';
try {
userId = Meteor.userId();
} catch (error) {
if (is.existy(ServerSession.get('documentOwner'))) {
userId = ServerSession.get('documentOwner');
} else {
userId = 'undefined';
}
}
if (this.isInsert) {
return userId;
} else if (this.isUpsert) {
return {$setOnInsert: userId};
} else {
this.unset();
}
},
denyUpdate: true
},
// Force value to be current date (on server) upon insert
// and prevent updates thereafter.
createdAt: {
type: Date,
autoValue: function () {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset();
}
},
denyUpdate: true
},
//other fields here...
});
server/methods.js
Meteor.methods({
createPlant: function () {
ServerSession.set('documentOwner', documentOwner);
var insertFieldOptions = {
'name' : name,
'type' : type
};
Plants.insert(insertFieldOptions);
},
//other methods here...
});
Note that I'm using the ff:
https://github.com/matteodem/meteor-server-session/ (for
ServerSession)
http://arasatasaygin.github.io/is.js/ (for is.existy)