I'm using the latest Ember (3.2).
I have made extension of text-area component:
app/components/enterable-textarea.js
export default TextArea.extend({
keyPress(event) {
if (event.keyCode === 13) {
console.info('e ', event);
}
}
});
I see the debug output in the console once I hit the 'Enter' key.
In my route template I have simple form like:
<form {{action "save" model.newNote on='submit'}}>
<div class="form-group">
<label for="tag">Tag</label>
{{input type="text" value=model.newNote.tag
placeholder="#anytag" class="form-control"}}
</div>
<div class="form-group">
<label for="note">Notepad</label>
{{enterable-textarea value=model.newNote.note
rows="6" class="form-control"}}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Ho do I pass form action to the component or fire the 'submit' event of the form?
I need to pass whole form to the route action by pressing the 'Enter'
You pass an action as a property and then call it as a function:
export default TextArea.extend({
onEnter: () => {}, //or function() {},
keyPress(event) {
if (event.keyCode === 13) {
this.get('onEnter')(); //or even this.onEnter();
}
}
});
{{enterable-textarea value=model.newNote.note
rows="6" class="form-control" onEnter=(action "save" model.newNote)}}
Read more about actions
Related
I'm creating and saving a form using Ember but when I reload the page the toggle keeping track of whether the form has been submitted or not resets to false.
I have a page where the default text is 'You have no account linked'. I then have a button that when pressed displays a form for the user to fill out information . When they click submit and save their information, the form disappears and renders some text about their account. When I reload the page however the text renders to the default 'You have no account linked', and when I click the submit form button, their information is populated in the form fields. How can I ensure that when the page is reloaded the text about the user account is displayed?
This is the controller for the page
export default Controller.extend({
isToggled: false,
emailConnected: false,
actions: {
submitImap(mailbox, toggle, email) {
this.get('ajax').request(`/api/accounts/${this.session.account.id}/mailboxes/imap`, {
method: 'POST',
data: mailbox
})
.then(() => Utils.notify("IMAP settings saved.", 'success'))
.catch(() => Utils.notify("Error saving IMAP account. Try again", 'error'));
this.send('contract', toggle);
this.send('expand', email);
},
disconnectIMAP(mailbox, property, email) {
this.get('ajax').request(`/api/accounts/${this.session.account.id}/mailboxes/imap`, {
method: 'DELETE',
data: {
user_id: mailbox.user_id
}
}).then(() => {
this.set(property, { smtp: {}});
})
.then(() => Utils.notify("IMAP removed. ", 'success'))
.catch(() => Utils.notify("Error removing IMAP account", 'error'));
this.send('contract',email );
},
expand: function(toggle) {
this.set(toggle, true)
},
contract: function(toggle) {
this.set(toggle, false)
}
}
});
This is the template handling the form submission
<h3>IMAP/SMTP</h3>
{{#if emailConnected}}
{{#if isToggled}}
<p> Edit your IMAP settings below </p>
{{else}}
<p>
You currently have IMAP account <strong>{{imapMailbox.username}}</strong>
connected for messaging.
</p>
<button {{action "disconnectIMAP" imapMailbox 'imapMailbox' 'emailConnected' }} class = 'btn btn-danger'>Disconnect</button>
{{/if}}
{{else}}
<p>
You currently do not have an account linked for messaging.
</p>
{{/if}}
{{#if isToggled}}
<form name='imap' class='modern-form full-width' {{action 'submitImap' imapMailbox 'isToggled' 'emailConnected' on="submit" }}>
<div class='row'>
<div class='col-sm-6'>
<h4>IMAP</h4>
<div class='form-group'>
<label>
Host
</label>
{{input type='text' required=true name='address' value=imapMailbox.address class='form-control'}}
</div>
<div class='form-group'>
<label>
Port
</label>
{{input type='text' required=true name='port' value=imapMailbox.port class='form-control'}}
</div>
<div class='form-check'>
{{input type='checkbox' name='ssl' checked=imapMailbox.ssl class='form-check-input'}}
<label for='ssl'>
SSL
</label>
</div>
<div class='form-check'>
{{input type='checkbox' name='starttls' checked=imapMailbox.starttls class='form-check-input'}}
<label>
TLS
</label>
</div>
<div class='form-group'>
<label>
Username
</label>
{{input type='text' required=true name='username' value=imapMailbox.username class='form-control'}}
</div>
<div class='form-group'>
<label>
Password
</label>
{{input type='password' required=true name='password' value=imapMailbox.password class='form-control'}}
</div>
</div>
<div class='col-sm-6'>
<h4>SMTP</h4>
<div class='form-group'>
<label>
Host
</label>
{{input type='text' required=true name='smtp_address' value=imapMailbox.smtp.address class='form-control'}}
</div>
<div class='form-group'>
<label>
Port
</label>
{{input type='text' required=true name='smtp_port' value=imapMailbox.smtp.port class='form-control'}}
</div>
<div class='form-check'>
{{input type='checkbox' name='smtp_ssl' checked=imapMailbox.smtp.ssl class='form-check-input'}}
<label for='ssl'>
SSL
</label>
</div>
<div class='form-check'>
{{input type='checkbox' name='smtp_starttls' checked=imapMailbox.smtp.enable_starttls_auto class='form-check-input'}}
<label>
TLS
</label>
</div>
<div class='form-group'>
<label>
Username
</label>
{{input type='text' required='true' name='smtp_username' value=imapMailbox.smtp.user_name class='form-control'}}
</div>
<div class='form-group'>
<label>
Password
</label>
{{input type='password' required='true' name='smtp_password' value=imapMailbox.smtp.password class='form-control'}}
</div>
</div>
</div>
<button type="submit" class='btn btn-success'>
Save
</button>
<button {{action 'contract' 'isToggled'}} class = 'btn btn-danger'>
Cancel
</button>
</form>
{{else}}
<button {{action 'expand' 'isToggled'}} class= 'btn btn-success'>
Connect email
</button>
{{/if}}
Right now, if I submit the form the behavior is as expected, displaying the current username of the account, but on reload the emailConnected variable resets to false and the default of 'you have no account connected' is present and when I click the form the values are populated.
If you reload the page (or) switch to a different route, the controller's property isToggled will reset to its initial state (i.e) to false in your case.
If you want to maintain the state and make use of the property isToggled at various parts of your application, you can use ember service
But in your case, you want to maintain the property state even after the page reloads. ember service doesn't maintain the state after the page reloads.
Here comes the use of browsers localStorage
So, in your case -
1) store the value of the property isToggled in browsers localStorage
import { computed } from '#ember/object';
export default Controller.extend({
isToggled: computed(function () {
// when the user visits the page for the very first time,
// isToggled value is set to false,
// from next time it gets the value from browsers localStorage.
if (localStorage.isToggled) {
return JSON.parse(localStorage.isToggled);
} else {
return false;
}
}),
...
actions: {
...
expand: function() {
localStorage.setItem('isToggled', JSON.stringify(true));
this.set('isToggled', true);
},
contract: function() {
localStorage.setItem('isToggled', JSON.stringify(false));
this.set('isToggled', false);
}
...
}
});
Now when the page is reloaded the isToggled property state doesn't change to the initial state.
You can find the isToggle browsers localStorage variable in your browsers developer tool: Application -> Local Storage tab
You could also use Ember Local Storage library to achieve this: https://github.com/funkensturm/ember-local-storage
I'm having trouble trying to get ember and sails playing nice together when it comes to relationships with belongsTo/hasMany.
I have a simple form:
<form {{action 'addMessage' on='submit'}}>
<div class="form-group">
<label for='name'>Title</label>
{{input value=title class="form-control" required="required"}}
</div>
<div class="form-group">
<label for='location'>User</label>
{{input value=user class="form-control" required="required" value=1}}</div>
<p>
<button class="btn btn-primary btn-block" type="submit">Create Message</button>
</p>
And a controller with the action
actions: {
addMessage: function() {
var newMessage = this.store.createRecord('message', {
title: this.get('title'),
user: this.get('user')
});
newMessage.save().then(function() {
}, function(error) {
console.warn('Save Failed.', error);
});
},
I'm just passing a string, and a value which matches a user id. When I look at what's being passed the title is fine, but the user id is null.
I'm using sails ember blueprints so it should work, but think I might be doing something wrong.
I've uploaded the sample code here if someone can take a look https://github.com/jimmyjamieson/ember-sails-example
On your user input is says value=1 which I think is changing what the controller is writing that property as.
so instead of
{{input value=user class="form-control" required="required" value=1}}
try
{{input value=user class="form-control" required="required"}}
Ok, fixed. I've added a repo for others to look at. It works with ember and ember-data 2.0 https://github.com/jimmyjamieson/ember-sails-relationships-hasmany-belongsto-example
When i first go the my login url, the inputs are correctly binded to the properties on my controller.
Then a press logout and what it does is transition back to the login page.
When i try to login again, it fails, because the input values arent binded to the controller, additionally i get this error:
Uncaught Error: Assertion Failed: Attempted to register a view with an id already in use: login
If i refresh the page it works.
Some of my code for references:
LoginRoute
export
default Ember.Route.extend({
setupController: function(controller) {
controller.reset();
},
beforeModel: function() {
if (!Ember.isEmpty(this.controllerFor('sessions.login').get('token'))) {
this.transitionTo('promotions');
}
}
});
LogoutRoute
export
default Ember.Route.extend({
beforeModel: function() {
this.controllerFor('sessions.login').reset();
this.transitionTo('sessions.login');
}
});
LoginAction on Controller
loginUser: function() {
var _this = this;
var login = this.get("login");
var pass = this.get("password");
Login Form
<form role="form" {{action 'loginUser' on='submit'}}>
<div class="form-group">
{{input type="text" class="form-control" id="login" placeholder="Login" value=login autofocus="autofocus"}}
{{input type="password" class="form-control" id="password" placeholder="Password" value=password}}
</div>
<div class="form-group">
<span class="input-group-btn">
<button class="btn btn-default" type="submit" ><span>Entrar</span></button>
</span>
</div>
</form>
After testing some more, i saw that the textFields are duplicating when i transition back to this page.
I really can't figure out, why
I feel as if this is a very simple problem to fix I am just not aware of how to fix it. Currently I have an outlet that displays a template like this:
user.hbs:
<div id="user-profile">
<img {{bind-attr src="avatarURL"}} alt="User's Avatar" class="profilePic"/>
<h2>{{name}}</h2>
<span>{{email}}</span>
<p>{{bio}}</p>
<span>Created {{creationDate}}</span>
<button {{action "edit"}}>Edit</button>
{{outlet}}
</div>
The template to be rendered at the outlet is this:
user_edit.hbs:
<div id="user-edit">
<h3>Edit User</h3>
<div class="panel-body">
<div class="row">
<label class="edit-user-label">Choose user avatar</label>
{{input class="form-control" value=avatarUrl}}
</div>
<div class="row">
<label>User name</label>
{{input class="form-control" value=name}}
</div>
<div class="row">
<label class="edit-user-label">User email</label>
{{input class="form-control" value=email}}
</div>
<div class="row">
<label class="edit-user-label">User short bio</label>
{{textarea class="text-control" value=bio}}
<div>
<div class="row">
<button {{action "save"}}>SAVE</button>
<button {{action "cancel"}}>CANCEL</button>
</div>
</div>
</div>
When I first visit the user route, the outlet does not display because the button has not been clicked. The button is hooked to a controller which takes care of the action. The action just transitions to the route where the template is displayed at the outlet. It appears just as expected but when I click on a different user model, the outlet from the previous user is still there without everything in the <div class="panel-body"> </div>. So Ember hides the panel-body div on transition but not the user-edit div. If you need more information I will be happy to provide it.
Here are the controllers:
userController:
App.UserController = Ember.ObjectController.extend({
actions: {
edit: function() {
this.transitionToRoute('user.edit');
}
}
});
Here is the userEditController:
App.UserEditController = Ember.ObjectController.extend({
actions: {
save: function() {
var user = this.get('model');
user.save();
this.transitionToRoute('user', user);
},
cancel: function() {
var user = this.get('model');
this.transitionToRoute('user', user);
}
}
})
Hi why dont you use {{#link-to 'edit' model}} instead of action ???
you can pass model to link-to so you dont have to get model in controller and then transitionToRoute
Look at this
I have a user settings form like so:
<script type="text/x-handlebars" data-template-name="settings">
<form class="form-horizontal user-form" {{action "update" on="submit"}}>
<div>
<label>First Name</label>
{{input type="text" value=firstName placeholder="First Name"}}
{{error.firstName}}
</div>
<div>
<label>Last Name</label>
{{input type="text" value=lastName placeholder="Last Name"}}
{{error.lastName}}
</div>
<div>
<label>Email Address *</label>
{{input type="text" value=email placeholder="Email Address"}}
{{error.email}}
</div>
</form>
</script>
In my route for this page, I define the model:
App.SettingsRoute = Ember.Route.extend({
model: function() {
return this.store.find('user', 1);
}
});
If things are left like this, the form will automatically populate with the values retrieved from the model. However, if I add a controller:
App.SettingsController = Ember.Controller.extend({
actions: {
update: function() {
// Do something
}
}
});
...They won't. So how do I use my model in conjunction with this controller to set the properties?
The way you defined your controller was as a regular Ember.Controller and not an Ember.ObjectController so the controller is not proxying the model. If you modify it to be like this:
App.SettingsController = Ember.ObjectController.extend({
actions: {
update: function() {
// Do something
}
}
});
Then it should still automatically populate with the values from the model.