Replace browser confirm() with other library like bootbox - ember.js

Browser native confirm dialog doesn't look good.
I have ember route wherein taking user confirmation to proceed if there are any unsaved changes.
I wanted to change the dialog with bootbox confirm dialog but that doesn't stop the execution as bootbox.confirm() method is async.
willTransition: function(transition){
// model dirty checking logic to set flag value
if(flag){
if(!confirm("Do you want to leave this page without save?")){
transition.abort();
}
}
}
Note: ES6 is not used in project

Since it doesn't block, the only way to do this is to:
Act as if the user said "No" then
If they click "Yes": programmatically restart whatever it was that was cancelled at step 1.

Related

ember waiting for user to complete the form

In ember, I have a form which ask the user their username and password for our remote server and then I want to verify the credentials by making an ajax call. Currently, I am using a custom made component which allows me to bind any action on clicking next or submit where I can verify the credentials and throw errors if needed. But once an error will occur, user cant click the next button (the way component is implemented) and hence second time validation is not happening. So, I thought to make a computed property which will look for username and password (and hence make ajax call when entered). But the problem with this approach is: every time something is entered in these boxes, computed property gets triggered which makes an ajax call (i dont want to make so many network calls for no purpose). Is there a way in ember where we can wait for user to finish the input and then invoke any kind of action?
Better approach is to use oninput with action:
<input oninput={{action "onInput" value="target.value"}}>
and then from action onInput debounce call to ajax function using debounceTask from ember-lifeline addon(this example), or using ember-concurrency:
actions: {
onInput(val){
debounceTask(this, 'sendAjax', val, 500);
}
}

Can I dynamically change the label of a Siebel button?

In our Siebel 7.8 (high interactivity) application, we have a form applet with a Pause / Resume custom button which does the following, depending on the current record's status:
If the status is "queued" or "active", it switches it to "paused".
If the status is "paused", it switches it back to whatever it was before.
If the status is another one ("completed", "error", etc), the button is disabled.
Is it possible to change the label dynamically? So that it would read Pause in the first case, and Resume in the second.
Off the top of my head the only way I can think of doing this would be with a browser script placed both in the Applet_Load and Applet_ChangeRecord events, something like:
var button = this.FindActiveXControl("Name Of My Button Control");
var status = this.BusComp().GetFieldValue("Status");
if (status == "paused") {
button.innerHTML = "Resume";
} else if ((status == "queued") || (status == "active")) {
button.innerHTML = "Pause";
} else {
// the button will be disabled via PreCanInvokeMethod, but we hide it too
button.style.visibility = "hidden";
}
Even if that worked (it should, but I haven't tried it)... I really hate browser scripts in Siebel, they always bring more trouble than solutions. Besides, I still would have to deal with changing the label when the button is clicked too... maybe checking the Applet_InvokeMethod browser event as well.
Is there any way of changing a button's label, based on the current record data, without coding1? All I have found searching online is this trick to change the applet label based on a calculated field, but nothing for buttons.
1: By without coding, I mean not coding the label change myself. It would be perfectly fine if I have to write a business service method to be invoked by Siebel somehow.
There are a few options potentially available:
We did something similar, but we are in a later Siebel version with Open UI. So instead of Browser Script we added code to custom Presentation Model and Physical Renderer JavaScript files. Even though you don't wish to, if you had to resort to something similar using Browser Scripts, you might prefer this over manipulating the text of one button.
I created two button controls: One that displayed Tag and the other Untag. They both call the same method. I added a flag field to the BC. (You might could do the same with a calculated field that is based on certain [Status] values.) In the JS files I put code to check that flag field and then, based on the flag field value, display one button and hide the other.
I did not start with Siebel until 8.1, so I cannot recall if this would be available in 7.8. And this only works on Order Management Applets with a class of CSSSWEFrameListHC (which is why I said "potentially available" options):
There exists an Applet User Property called Hide Control n [See Siebel Developer's Reference v7.8 -> Ch 4: User Properties -> Setting Numbered Instances of a User Property for the use of n in User Properties.]
First, create two separate controls - one that displays Pause and the other Resume. The User Property could be used something like this:
Applet User Properties
Name Value
Hide Control 'Name Of My Pause Button Control', '[Status] = "paused"'
Hide Control 1 'Name Of My Resume Button Control', '[Status] = "queued" OR [Status] = "active"'
You could possibly OR all the other [Status] values into these if you wanted to hide it and not just disable it.
Use Toggle Applets. [See Configuring Siebel eBusiness Applications v7.7 -> Ch 13: Configuring Screens and Views -> Example of Configuring Applet Toggles.]
Copy your existing Applet that has Resume, and modify that button Control in the copy to display Pause. Name the new Applet something like My Form Applet - Pause Button.
Then in Tools drill into your existing Applet, click the Applet Toggle child object, add a New Record, and make it something like this:
If you want this to toggle immediately when the [Status] changes, you'll need to set Immediate Post Changes to TRUE on the [Status] field on the BC. (This could cause performance issues, so be mindful.) Otherwise the Applet won't toggle until the record is saved.
Or you could possibly create a calculated flag field on the BC based on [Status] values, set it's Immediate Post Changes to TRUE, and base the Applet Toggle on that field.
DISCLAIMER: Other than our version of #1, I have not attempted any of these.

Preventing code to run multiple times in action

I have code in action that works fine if the person clicks only a single time on the button however if they click multiple time fast on the button, that code get run many times and creating weird issues. Anyone know how to prevent this from happening?
First solution is disabling the button after clicked by setting the disabled property of the button.
Although setting disabled property of the button can completely solve the solution; spreading the re-enable logic to the code is not nice, when some async operation is being executed.
Further more, re-enabling the button can be more complex when you have some other conditions to disable the button. (e.g. If a field on the form has an invalid value, you may again want to disable the button.)
We mostly prefer ember-concurrency addon for such needs. Its task structure provides a more readable code for most cases.
You want to set the disabled attribute of your <button>/<a> to prevent users from triggering it again while you are processing the first action. To do so, I typically use a flag to determine if that action is currently processing. If the flag is set, set the disabled attribute. It's also a good idea to have a guard statement in your action as well. As some browsers may not respect the disabled attribute.
Controller/Component:
import Ember from 'ember';
import moment from 'moment';
export default Ember.Controller.extend({
isLoading: false,
actions: {
yourAction() {
// It's a good idea to use a guard statement here as well. Just incase the browser doesn't respect the `disabled` attribute.
if(this.get('isLoading')) {
return;
}
this.set('isLoading', true);
// Do your work here. If it's a promise, use `finally` to unset the flag to avoid forever loading on errors.
this.set('isLoading', false);
}
}
}
Template:
<button {{action 'yourAction'}}
disabled={{isLoading}}>
Your Action
</button>
Using this method, you can also add some loading styling on your action as well. Perhaps a spinner as pseudo element:
Template:
<button class="{{if isLoading 'loading'}}"
{{action 'yourAction'}}
disabled={{isLoading}}>
Your Action
</button>
Edit
As ykaragol mentioned, if you want/can add a library to your Ember app, ember-concurrency will greatly simplify the native Ember example above. They have a guide here which refactors the example above into a more readable example using ember-concurrency.
Add this to your button.
onclick="this.disabled=true;"
Example:
<button onclick="this.disabled=true;">Click</button>
When you click the button, the onclick runs immediately and disables the button to prevent additional clicks.

Force reload of dirty/invalid model in Ember

I am trying to build out edit functionality for a Goal record. On the Goal index page, there is an edit button next to each goal. When clicked, each field becomes editable. Upon clicking Save, the changes are saved to the server. So far so good.
There is also a Cancel button. When a user clicks it, I need to reset the state of the model to what it was before they changed things. goal.rollback() in the controller works fine for this. Except, if the user has already clicked Save but there were server side validation failures. In this case, attempting to rollback() throws Uncaught Error: Attempted to handle event `reloadRecord` on <App.Goal:ember123:1234> while in state root.loaded.updated.invalid.
If instead I try to goal.reloadRecord I get Uncaught Error: Attempted to handle event `reloadRecord` on <App.Goal:ember123:1234> while in state root.loaded.updated.invalid.
Same deal with goal.unloadRecord. I have tried massaging the state like this:
state = goal.get('currentState') #this code makes me sad.
state.isValid = true
state.isError = false
And like this:
goal.transitionTo('loaded.saved')
To no avail. Is make zero sense to me the reloading or unloading a record should be statefull.
Any assistance would be greatly appreciated. Again, I'm trying to take a dirty, invalid record in ember and get it back to a happy state either by rolling back changes, or just reloading it from the server.
EDIT: Ember-data v1.0.0-beta.3-4-g169793e, ember Version: 1.1.2
Here's a working example, change the color then hit save.
http://emberjs.jsbin.com/OxIDiVU/44/edit
PR submitted https://github.com/emberjs/data/pull/1590

Access content property in the debugger

how can i access the content property of a controller within the chrome debugger.
I really try to find a way to debug my application. So far i can't find a way to do that.
Thank you
Alex
add the statement
debugger;
in the method you want to debug,
Open Google Chrome, CTRL+SHIFT+i
Hit the URL of your application, navigate to the state where you think the code would run
Google Chrome automatically stops at the debugger; statement and focuses you to the sources/scripts tab as you can see in the picture
Inside the Watch expression tab click on the "+" too evaluate code in your case it would be
this.get("content");
As long as you have this breakpoint you can switch to the console panel and execute the code in that context, whenever you are done you can either close the panel by clicking CTRL+SHIFT+I or the close button down there, you can add breakpoints manually by clicking on the line number as well , Hope this helps
For more info
I'm using Ember Extentions which is not ready yet but certainly usable.
There are 2 possibilities
Use the Ember Inspector Tool for Chrome: It is not officially released yet, but from what i have heard it seems usable. I had no time to try it myself yet, but here is an article telling you how to install and use it.
Get access to your controller in the console of your browser. And then examine it as you like. Here is the code to get access to your controller.I use it myself in my app for debugging:
// i assume that your Ember.Application is stored in the global var App
var App = Ember.Application.create({
getController : function(name){
return this.__container__.lookup("controller:" + name);
}
});
// now you can use it like this. To get the users controller (App.UsersController) just use this in the console:
App.getController("users")