The following works. I can use my component to save new addresses. When the success promise is resolved, it transitions to the same route: _this.transitionToRoute('checkout.address.index')
The issue is, the form still contains the same values of the new address. I need to form to be cleared. How do I go about that?
// Controller
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
save: function(address) {
var _this = this;
this.store.createRecord('address', address.getProperties('address1', 'address2', 'city', 'postalCode')).save().then(function(){
_this.transitionToRoute('checkout.address.index');
}, function() {
// Need this promise, so we can render errors, if any, in the form
});
}
}
});
// Template
{{address-form action='save'}}
// Component object
import Ember from 'ember';
export default Ember.Component.extend({
address: function() {
return Ember.Object.create();
}.property(),
actions: {
save: function() {
this.sendAction('action', this.get('address'));
}
}
});
// Component template
<form {{action 'save' on='submit'}}>
<p>
<label>Address:
{{input value=address.address1 placeholder='11 Mars Street'}}
</label>
{{#each error in errors.address1}}
<br />{{error.message}}
{{/each}}
</p>
<p>
{{input value=address.address2 placeholder='Bel Air 1 Village'}}
{{#each error in errors.address2}}
<br />{{error.message}}
{{/each}}
</p>
<p>
<label>City:
{{input value=address.city placeholder='Makati'}}
</label>
{{#each error in errors.city}}
<br />{{error.message}}
{{/each}}
</p>
<p>
<label>Postal code:
{{input value=address.postalCode placeholder='1209'}}
</label>
{{#each error in errors.postalCode}}
<br />{{error.message}}
{{/each}}
</p>
<input type='submit' value='Next'/>
<button {{action 'cancel'}}>Cancel</button>
</form>
I'd suggest something like this (note, edited the code a little bit for readability):
export default Ember.Controller.extend({
actions: {
save: function(address, component) {
var controller = this;
var addressProperties = address.getProperties('address1', 'address2', 'city', 'postalCode');
var newAddress = controller.store.createRecord('address', addressProperties);
function onSuccess() {
controller.transitionToRoute('checkout.address.index');
component.reset());
}
function onFailure() {
// Need this promise, so we can render errors, if any, in the form
}
newAddress.save().then(onSuccess, onFailure);
}
}
});
// Component object
import Ember from 'ember';
export default Ember.Component.extend({
address: function() {
return Ember.Object.create();
}.property(),
reset: function() {
this.set('address', Ember.Object.create());
},
actions: {
save: function() {
var component = this;
component.sendAction('action', component.get('address'), component);
}
}
});
Related
I have a component which contains a switch and a yielded form.
The switch changes the model used for the yielded form.
In the said form, I have a textarea whose value comes from the model. When I update the model in the component, the textarea is bent to the correct model but the value inside it doesn't update. I can't figure out how to do it
I'm using Ember 1.13.
Here is my component:
import Ember from 'ember';
const { computed } = Ember;
export default Ember.Component.extend({
// Properties
switchField: null,
defaultModel: null,
specificModel: null,
activeModel: computed('switchField', 'defaultModel', 'specificModel', function() {
if (this.get('switchField')) {
return this.get('defaultModel');
} else {
return this.get('specificModel');
}
}),
editDisabled: computed('switchField', function() {
if (this.get('switchField')) {
return true;
} else {
return false;
}
}),
renderSwitch: function() {
Ember.run.schedule('afterRender', this, function() {
$('.toggle-switch').bootstrapToggle();
});
}.on('init'),
actions: {
reflectChange: function(value) {
this.set('switchField', value);
this.rerender();
}
}
});
The template:
<div class="col-xs-12">
<input data-toggle="toggle" data-onstyle="success" data-offstyle="danger" class="toggle-switch" type="checkbox" checked={{switchField}} onchange={{action "reflectChange" value="target.checked"}} />
<br>
<br>
</div>
{{ yield activeModel editDisabled }}
And how it is used:
{{#inherit-switch switchField=warehouse.companyInheritance.inheritCarrierProcedure defaultModel=company specificModel=warehouse as |activeModel editDisabled|}}
<div class="col-xs-12">
{{#form-group value=activeModel.errors.carrierProcedure }}
<label class="control-label" for="carrierProcedure">Procédure coursier</label>
{{textarea class="form-control" id="carrierProcedure" value=activeModel.carrierProcedure disabled=editDisabled}}
{{/form-group}}
</div>
{{/inherit-switch}}
I tried to rerender the component but it doesn't work.
I don't understand why the value doesn't change since the textarea gets correctly enabled/disabled when I toggle the switch.
Thanks for your help.
I am using a subexpression at {{input value=(cents-to-dollars model.amountInCents)}}. It is using a custom helper to convert the value from cents to dollars. My API returns cents.
However in the controllers save action, console.log(this.get('model.amountInCents')); returns undefined. Am I missing something? Maybe name or valueBinding in the input helper?
If I remove the subexpression. console.log(this.get('model.amountInCents')); outputs fine.
// Routes
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('product', params.product_id);
}
});
// Controller
export default Ember.Controller.extend({
actions: {
save: function() {
console.log(this.get('model.amountInCents')); // returns undefined
var _this = this;
var dollars = this.get('model.amountInCents');
var amountInCents = dollars / 100;
this.get('model').set('amountInCents', amountInCents);
this.get('model').save().then(function(product){
_this.transitionToRoute('admin.products.show', product);
}, function() {
// Need this promise, so we can render errors, if any, in the form
});
return false;
},
cancel: function() {
this.transitionToRoute('products.show', this.get('model'));
}
}
});
// Template
<form {{action "save" on="submit"}}>
<p>
<label>Name:
{{input value=model.name}}
</label>
</p>
<p>
<label>Amount in cents:
{{input value=(cents-to-dollars model.amountInCents)}}
</label>
</p>
<input type="submit" value="Save"/>
<button {{action "cancel"}}>Cancel</button>
</form>
First of all, (at least in version 1.9.1) what you are proposing doesn't really work (see here - the value appears outside of the input field). The real problem, I think, is that you are not binding to a property and instead are binding to a string returned from a helper (which is not what you want).
So, what can you do?
You can set up a dollars computed property as follows:
App.IndexController = Ember.ObjectController.extend({
dollars: function(key, value){
if (arguments.length > 1) {
var dollars = value;
this.set('amountInCents', parseInt(dollars) * 100);
}
return this.get('amountInCents') / 100;
}.property('model.amountInCents')
});
Full working example here
I am still learning Ember and have encountered a problem with keep consistent behavior when showing/hidding certain elements in the template. I have the following controller
import Ember from 'ember';
export default Ember.ArrayController.extend({
actions: {
newCalendar: function() {
this.set('showCalendarForm', true);
},
hideNewCalendar: function() {
this.set('showCalendarForm', false);
this.set('calendarName', '');
},
showCalendarForm: false,
createCalendar: function() {
var name = this.get('calendarName');
if (!name) { return; }
if (!name.trim()) { return; }
var calendar = this.store.createRecord('calendar', {
name: name
});
this.set('calendarName', '');
this.set('showCalendarForm', false);
calendar.save();
},
}
});
and a template
{{#if showCalendarForm}}
<div class="input-group">
{{input
class = 'form-control'
id = 'newCalendar'
type = 'text'
placeholder = 'New calendar'
value = calendarName
autofocus = 'autofocus'
focus-out = 'hideNewCalendar'
action = 'createCalendar'
}}
</div>
{{else}}
<button class="btn btn-sm btn-primary" {{action "newCalendar"}}>New</button>
{{/if}}
Problem is that the input field only gets autofocused the first time I click the button, and on subsequent clicks, the input gets displayed, but not autofocused. How can i fix this?
I'm building an app that has the following code:
Routes:
App.Router.map(function() {
this.resource('gradebooks', function() {
this.resource('gradebook', { path: ':gradebook_id' });
});
});
App.IndexRoute = Em.Route.extend({
redirect: function() {
this.transitionTo('gradebooks');
}
})
App.GradebooksRoute = Em.Route.extend({
setupController: function(controller, model) {
Em.$.getJSON('/data/gradebooks/get', function(data) {
controller.set('model', data);
});
}
});
App.GradebookRoute = Em.Route.extend({
model: function(params) {
var id = params.gradebook_id;
return Em.$.getJSON('/data/gradebooks/get/' + id);
}
})
Controllers:
App.GradebooksController = Em.ArrayController.extend({
isActive: false,
actions: {
createGradebook: function(newTitle) {
var self = this;
if(newTitle.trim()) {
Em.$.get('/data/gradebooks/add/' + newTitle, {}, function(json) {
Em.$('#create-gradebook-modal').modal('hide').find('input').val('');
self.transitionToRoute('gradebook', json.id);
}, 'json');
}
}
}
});
Templates (gradebooks.hbs):
<div class="sidebar">
<div class="btn-container">
<button class="btn btn-block btn-info" data-toggle="modal" data-target="#create-gradebook-modal">
<i class="fa fa-book"></i>
Create Gradebook
</button>
</div>
<ul>
{{#each}}
<li {{bind-attr class="isActive:active"}}>
{{#link-to "gradebook" _id}}
{{title}}
{{/link-to}}
</li>
{{/each}}
</ul>
</div>
<div class="content">
<div class="container-fluid">
{{outlet}}
</div>
</div>
Templates (gradebook.hbs):
<h1>{{title}} <small>{{_id}}</small></h1>
<div class="btn-container">
<button class="btn btn-default"><i class="fa fa-pencil"></i> Rename</button>
<button class="btn btn-danger"><i class="fa fa-trash-o"></i> Trash</button>
</div>
What I'm having trouble with is under the GradebooksController.actions.createGradebook, I send a request to create the model and then I transition to the gradebook I just created. The creation and transition works just fine, but I want the sidebar (gradebooks.hbs) to show the newly created gradebook.
I think it has something to do with updating the model in the GradebooksRoute. How can I make it fetch for the models from the server again after creating a gradebook.
To elaborate on #fanta's comment, you'll want to do something like this:
App.GradebooksController = Em.ArrayController.extend({
isActive: false,
actions: {
createGradebook: function(newTitle) {
var self = this;
if(newTitle.trim()) {
var gradebook = Em.$.getJSON('/data/gradebooks/add/' + newTitle, {}, function(json) {
Em.$('#create-gradebook-modal').modal('hide').find('input').val('');
self.transitionToRoute('gradebook', json.id);
}, 'json');
self.get('content').pushObject(gradebook);
}
}
}
});
I have problem with observes. When template is loaded, observers on form fields are fire immediately, before any user action. Thanks for any ideas how to fix it :)
This is my route:
App.AccountsNewRoute = Ember.Route.extend({
model: function() {
return App.Account.create({});
}
});
This is my controller:
App.ExpensesNewController = Ember.ObjectController.extend({
...
amountValidate: function() {
console.log("amount changed");
}.observes("amount"),
...
});
This is my template:
...
<div class="small-10 large-10 columns">
{{input value=amount type='text'}}
</div>
...