For some reason an RSVP promise I created in an action stopped working for me and I can't figure out what when wrong where to make it stop working.
I have a component that sends an action and waits for a response
// COMPONENT IN ITEM ROUTE
callAjaxAction() {
this.setProperties({working:true});
Ember.RSVP.cast(this.attrs.action()).finally(() => {
Ember.$('.draggable').animate({
left: 0
});
this.setProperties({working:false});
});
}
This particular instance of the component calls this action in the controller
// IN ITEM CONTROLLER
placeBid() {
return new Ember.RSVP.Promise((resolve,reject) => {
if(this.get('winning')) {
this.get('notification')._confirm({message: "You are currently the highest bidder, would you like to continue with your bid?",isConfirm: true}).then(()=>{
console.log('confirmed');
this.send('placeBidActual').then(()=>{
resolve();
}).catch(()=>{
reject();
});
return true;
}).catch(()=>{
resolve();
console.log('denied');
return false;
});
} else {
setTimeout(()=>{
this.send('placeBidActual').then(()=>{
resolve();
}).catch(()=>{
reject();
});
},500);
}
});
}
This action is calling a confirm method on a service and waiting for the user to hit yes in the case of the user already winning this item. Otherwise I'm just calling the actual ajax action right away, that action looks like this
// IN ITEM CONTROLLER
placeBidActual() {
return new Ember.RSVP.Promise((resolve,reject) => {
Ember.$.ajax({
...
}).then((response)=>{
(do some stuff with the response)
resolve();
}, (reason)=>{
(do something with rejection reason)
reject(reason);
});
});
}
In the console I'm getting the error
Uncaught TypeError: Cannot read property 'then' of undefined
On the line where it states this.send('placeBidActual')
UPDATE:
Here is maybe a better explanation to the expected process flow.
The user attempts to place a bid, the user swipes a component over to indicate they wish to bid. The UI at this point shows a loading indicator and waits for the ajax action to complete before it resets the UI.
If the user is not already the highest bidder of the item it will go straight to the ajax action and upon completion signifies to the component to reset the UI.
However, if the user is the highest bidder of the item it should instead show a confirm message (using the notification service I have setup) and wait for the user to either confirm or deny. If they deny it just cancels and signifies to the component to reset the UI. If the user confirms then it calls the ajax action and upon completion signifies to the component to reset the UI.
Updated answer:
This isn't working because send doesn't return the value of the action.
I suggest moving the placeBidActual action to a method on the controller and call it like any normal method. This way you will get the return value and be able to call .then on it.
You should pass a function, whithout invoke it.
Instead this:
Ember.RSVP.cast(this.attrs.action()).finally(() =>
Try it:
Ember.RSVP.cast(this.attrs.action).finally(() =>
Invoking the funcion this.attrs.action() does it pass undefined for the Promise.
Related
I'm using Inertia/Laravel/VueJs. I have a page with many posts and each post can be marked as completed. When a post is marked as completed on the front-end I have a v-bind which toggles a CSS class which should be applied to completed tasks.
The behaviour I would like is: a user scrolls down a page, clicks the completed button, and the back-end sends that newly updated data to the front-end, making the v-bind true, causing the CSS class to be applied without jumping to the top of the page.
With the code below I can click the completed button, and it is updated in the database, but that new data isn't sent to the front-end.
Controller:
public function markAsCompleted(Request $request)
{
$post = Post::find($request->id);
$post->completed = true;
$post->save();
return Redirect::route('posts');
}
Javascript function called at click of completed button:
completed(id) {
this.completedForm.put(`/endpoint/completed/${id}`, {
preserveScroll: true
});
},
If I change the Javascript function to:
completed(id) {
this.completedForm.put(`/endpoint/completed/${id}`, {
preserveScroll: true,
onSuccess: () => {
Inertia.get('posts');
},
});
},
In this case, the new data is returned to the front-end with the post being marked as completed, but the preserveScroll doesn't work, and jumps the user to the top of the page.
Any ideas on how to get my desired use case working? Users could have hundreds of posts so I can't have the page jump up to the top every time.
Thank you for any help!
To update your app while preserving the state:
Inertia.get('posts', params, {
preserveState: true,
})
One way, not the cleanest, but it is a solution. Just click "Completed Button" to send a request to the backend, and ONLY to check if the response is success, then update that task in frontend as complete. So you just update (add class) this element and you don't rerender whole DOM. Because, if you get success response, thats done in the backend for sure.
I am trying to pop up a Confirmation Dialog (dialog.confirm(options)) as soon as one clicks on Submit Button on my Suitelet. For this, I am using saveRecord Entrypoint in Clientscript. Below is the code
function saveRecord() {
//alert('Inside Save Record');
var options = {
title: "I am a Confirmation",
message: "Press OK or Cancel"
};
function success(result) {
console.log('Success with value ' + result);
}
function failure(reason) {
console.log('Failure: ' + reason);
}
dialog.confirm(options).then(success).catch(failure);
}
Upon execution, I am getting the dialog box, but on clicking OK I am unable to move further. (that is from Suitelet GET to Suitelet POST).
Please Note - I am using SuiteScript 2.0
Given the code provided when you press "Ok" there is no further actions (redirect to Suitelet) defined. If you want to trigger the Suitelet after user presses okay add the redirect to the success function. The "redirect.toSuitelet(options)" method is not available for Client scripts but you can use window.open(URL); to point the user to the suitelet.
On saveRecord, you either return true; to proceed or return false; to stay on the page.
If you return true from the success then it won't serve to confirm your saveRecord. It's returning from a different context. One workaround could be to use the native browser window.confirm as this executes synchronously.
In my application, I am using actions to do all of my ajax calls. When the results come back, it dispatches them to the reducer, which then puts it in the store. My component is bound to the property and will then be able to get it from the store.
However, I am having an issue trying to figure out the best way to do form submissions. From a listing page, a user can click on a link from any row to open a modal. This modal has a form in it. When the form is filled out, it will then pass the data along to an action, which will submit it. The only response from a valid submission is a HTTP 200.
Without using callbacks, how would the modal know that the ajax call is complete, so it can close itself? As of now, I have a flag in the store called form.processing. This is default to false, and the action will set it to true when it begins and false when its done. The component watches this and then knows when it goes from true to false and knows everything is done. However, I feel like there should be a better way.
Or should I be using callback in forms, even though we don't follow that process for any other ajax call?
Here are following pseudo code can help you:
constructor () {
this.state = {
disaplyModalPopup: false;
}
}
handleSubmit = () => {
this.setState({disaplyModalPopup: true})
let payLoad = { 'Key':this.state.something }
this.props.hitAPI(payLoad).then((res) => {
if (res.data.success) {
this.setState({
'disaplyModalPopup': false
})
}else{
this.setState({
'disaplyModalPopup': true,
'errorMessage': 'something wend wrong'
})
}
})
}
rendor (){
let errorMessage = {this.state.errorMessage}
let disaplyModalPopup = {this.state.disaplyModalPopup}
return (
{disaplyModalPopup ? <modal> </modal> : ''}
{ errorMessage? 'errorMessage': ''}
)
}
Here I have handled your modalPopup with disaplyModalPopup state.
And After get in the response saved in reducer, it is changes as {disaplyModalPopup: false}
And modalPopUp HTML will disappear.
But in case your API get in failed while making response.
So that case: i have handle as error message in as text
errorMessage where you can show your error message. So that Modal is closed side by side.
I am experimenting with the new way of handling page events in jqM and have run into a curious issue. When handling the pagecontainerbeforechange event
$(document).on('pagecontainerbeforechange',function(e,u){test(e,u,'changing');})
function test(e,u,msg){console.log($(u.toPage));}
Attempting to put a jQuery object wrapper around u.toPage - as done above - produces strange behavior.
Check out this fiddle to see what I mean
Click on the Second Page button and then view the console. Nothing will happen (the second page is not shown) and you will see a message along the lines of *Uncaught error:syntax error, unrecognized expression http://jsfiddle.net/egn7g5xb/1/show/#second
Now comment out Line 7 and run the fiddle again. No such issue this time and the second page gets shown.
Perhaps someone here might be able to explain what is going on here?
On initial run, jQuery Mobile creates a fake page before navigating to first page in DOM. At that stage, pagecontainerbeforechange fires twice and returns .toPage as an object.
Later on, upon navigating to other pages, it fires twice again; however, it returns a string first time (URL/hash) and second time it returns an object which is the page itself.
Therefore, when using that event, you have to determine whether .toPage is an object or a string.
$(document).on("pagecontainerbeforechange", function (e, data) {
if (typeof data.toPage == "string") {
/* parse url */
}
if (typeof data.toPage == "object") {
/* manipulate page navigating to */
}
});
Note that pagecontainerbeforetransition is similar to beforechange, however, it fires once and returns .toPage as an object.
First, create your pagecontainer events within $(document).on("pagecreate", "#first", function(){ .. }).
Then the selector for these events should be $(":mobile-pagecontainer") or $("body") NOT $(document).
function test(e,u,msg)
{
console.log(msg);
var IsJQ = u.toPage instanceof $;
console.log(IsJQ);
if (IsJQ){
console.log(u.toPage.data());
} else {
console.log(u.toPage);
}
console.log('---');
}
$(document).on("pagecreate", "#first", function(){
$(":mobile-pagecontainer").on('pagecontainerbeforechange', function (e, u) {
test(e,u,'changing');
});
$(":mobile-pagecontainer").on('pagecontainerchange',function(e,u){
test(e,u,'changed');
});
});
Updated FIDDLE
I have a BackboneJS App where I fetch a bunch of collections. Now I want to apply some sort of loader to indicate that the collection is loading and the user gets to know that something is happening. So I want to use the .ajaxStart() and .ajaxStop()-method. So I was thinking about something like this:
this.artistsCollection.fetch(
$(document).ajaxStart(function () {
console.log('ajax start');
$('.someDiv').addClass('TEST');
}),
$(document).ajaxStop(function () {
console.log('ajax stop');
// stop doing stuff
})
);
Issue is that first time I trigger the .fetch() my console says ajax stop and the class is not applied!?!? Second time I trigger the .fetch() it works like it should and the class gets applied. Does anyone know whats the issue?
Please help anyone?
You're passing the returned result of adding the two event handlers with jQuery as parameters to the Collection fetch method. The Backbone Collection fetch method receives an options object which can include a success callback (see documentation).
I think if you move the listeners out of the method call it should work as you expect:
// Global AJAX listeners
$(document).ajaxStart(function () {
console.log('ajax start');
// do stuff
});
$(document).ajaxStop(function () {
console.log('ajax stop');
// stop doing stuff
});
this.artistsCollection.fetch();