Im new to Ember and I am trying to create a record by submitting a form. This is the code I've written so far:
App.CharactersNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('character', {name: '', race: ''});
}
});
<form {{action "createCharacter" on="submit"}}>
<div class="form-group">
<label>Name</label>
{{input value=characterName class="form-control"}}
</div>
<div class="form-group">
<label>Race</label>
{{input id=characterRace class="form-control"}}
</div>
{{#link-to 'characters'}}<button class="btn btn-default">Back</button>{{/link-to}}
<button class="btn btn-default" type="submit">Create</button>
</form>
App.CharactersNewController = Ember.ObjectController.extend({
actions: {
createCharacter: function() {
var name = this.get('characterName'),
race = this.get('characterRace');
if (!name || !race) { return false }
// create new character
var character = this.store.createRecord('character', {
name: name,
race: race
});
this.set('characterName', '');
this.set('characterRace', '');
character.save();
}
}
})
Right now, the code stops at the var character = this.store.createRecord line in the controller, but no errors are raised in the console
Thanks
Related
We have a iOnic based project and during check out users can add new address to their account.
This is what my controller file look like
$scope.addAddress = function() {
$scope.showLoading();
addressService.addUserAddress($scope.userDetails.userID, $scope.addAddressdata.houseNo, $scope.addAddressdata.street, $scope.addAddressdata.AddDesc, $scope.addAddressdata.LID)
.success(function(response) {
console.log(response);
$scope.hideLoading();
$scope.closeModal();
$scope.getAllAddress();
});
};
$scope.getAllAddress = function() {
addressService.getAllLocations()
.success(function(response) {
$scope.locations = response;
$scope.hideLoading();
});
};
And this is what my services file look like
function() {
"use strict";
var myApp = angular.module('jobolo');
myApp.service('addressService', ['$http', 'appVariableService', function($http, appVariableService) {
var addressService = this;
addressService.getAllLocations = function() {
var data = {
appid: appVariableService.get('appId')
};
return $http.post(appVariableService.get('baseURL') + 'useraddress/getMyLocation', data);
};
addressService.getUserAddress = function(userId) {
return $http.get(appVariableService.get('baseURL') + 'useraddress/myaddress/' + userId, {cache:false});
};
addressService.addUserAddress = function(userId, houseNo, street, adddesc, lid) {
var data = {
appid: appVariableService.get('appId'),
userid: userId,
houseno: houseNo,
street: street,
adddesc: adddesc,
lid: lid,
};
return $http.post(appVariableService.get('baseURL') + 'useraddress/adAdd' , data);
};
}]);
})();
When I add a new address it does add to the database but isn't showing in list. I tried adding $scope.refreshList(); to the code too. When I log out and come back it does show up. Thank you for your help in advance
View Codes are
<ion-view class="main-content">
<ion-nav-buttons side="secondary">
<button menu-toggle="right" class="button button-icon icon ion-navicon"></button>
</ion-nav-buttons>
<div class="bar bar-subheader">
<h2 class="title">Select Address</h2>
</div>
<ion-content class="has-subheader" scroll="true" overflow-scroll="true" style="bottom:57px">
<div class="list">
<ion-radio
ng-model="data.selectedAddress"
ng-value="address"
ng-repeat="address in userAddresses"
class="radio-nowrap"
>
House No. {{address.HouseNo}}, {{address.Street}}, {{address.AddDesc}}, {{address.AreaName}}, {{address.City}}
</ion-radio>
</div>
<!-- <div class="row">
<div class="col location-form">
<button class="button" type="button" ng-click="openModal()">Add New Address</button>
</div>
</div> -->
</ion-content>
<div class="row" style="position: absolute;bottom: 0;padding:0">
<div class="col location-form">
<button class="button" type="button" ng-click="openModal()">Add New Address</button>
</div>
<div class="col location-form">
<button class="button" type="button" ng-disabled="!data.selectedAddress" ng-click="selectAddress(data.selectedAddress)">Select Address</button>
</div>
</div>
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);
}
}
});
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);
}
}
}
});
when ember.js tries to render my template containing the following bindAttr. the following exception is thrown in handlebars.js
Uncaught TypeError: Object [object Object] has no method 'replace' handlebars.js:848
bind attr tag:
<div class="postWrapper" {{bindAttr style="display:none"}}>
Update
this also happens when i use the action helper
<div {{action Toggle}} class="btn pull-right">
<i class="postToggler icon-chevron-down " ></i>
</div>
Update Full Code
Template
<script type="text/x-handlebars" data-template-name="Composer">
<div class="postWrapper">
<div class="postContentWrapper" {{bindAttr style="controller.display"}}>
<div class="row-fluid">
<div class="pull-left span10">
To :
<input id="test2" type="text" style="margin-top: 7px;width:90%" />
</div>
<div {{action Toggle}} class="btn pull-right">
<i class="postToggler icon-chevron-down " ></i>
</div>
</div>
<div class="row-fluid" style="height:100%" >
<div id="wmd-button-bar" style="width:48%;display:inline-block" ></div>
<div class="pull-right">
<a>Hide preview</a>
</div>
<div class="wmdWrapper" style="height:80%">
<div class="wmd-panel" style="vertical-align: top;">
<textarea class="wmd-input" id="wmd-input" style="height: 100%;"></textarea>
</div>
<div id="wmd-preview" class="wmd-preview pull-right"></div>
</div>
<br />
</div>
<div class="row-fluid">
<div class="span6 ">
<p>
Tags :
<input id="test" type="text" style="width:80%"/>
</p>
</div>
<div class="span2 pull-right">
<button id="btnSubmitPost" class="btn btn-success pull-right">{{controller.buttonText}}</button>
<button id="btnCanelPost" class="btn btn-warning pull-right">Cancel</button>
</div>
</div>
<div class="row-fluid">
</div>
</div>
</div>
</script>
View and render
/*
MODES
NEW
REPLY
*/
Thoughts.ComposerController = Ember.Object.extend({
mode: 2,
visible: false,
messageContent: "",
buttonText: function () {
switch (this.get("mode")) {
case 1: return "Post";
case 2: return "Reply";
}
}.property(),
display: function () {
if (this.get("visible")) {
return 'display:block';
} else
return 'display:none';
}.property(),
Toggle: function(){
console.log('Helllo');
}
});
Thoughts.ComposerController = Thoughts.ComposerController.create();
Error Information
object dump
string: "data-ember-action="1""
__proto__: Object
constructor: function (string) {
toString: function () {
__proto__: Object
Crashes on the replace method, because the method replace is undefined
Handlebars.Utils = {
escapeExpression: function (string) {
// don't escape SafeStrings, since they're already safe
if (string instanceof Handlebars.SafeString) {
return string.toString();
} else if (string == null || string === false) {
return "";
}
if (!possible.test(string)) { return string; }
----> return string.replace(badChars, escapeChar);
},
So first of all you need to define only need to define the controller. You don't have to create an instance. Ember will do it for you when application initialize.
If you define a property that is observing another in other words its value depends on another, you need this to specify as parameter to property helper.
Thoughts.ComposerController = Ember.Controller.extend({
mode: 2,
visible: false,
messageContent: "",
buttonText: function () {
switch (this.get("mode")) {
case 1: return "Post";
case 2: return "Reply";
}
}.property('mode'),
display: function () {
return 'display:' + this.get('visible') ? 'block' : 'none';
}.property('visible'),
Toggle: function () {
this.toggleProperty('visible');
this.set('mode', this.get('mode') == 2 ? 1 : 2);
}
});
Template itself seems valid.
You can get this working by creating a composer route like this:
this.route('composer');
or by rendering it in another template like this:
{{render 'composer'}}
That should be answer to your question. BUT
Wouldn't be better to use {{if}} helper for showing some content inside of template based on a condition?
i finally found some time to work on this again.
all i did was replace the ember and handlebars js files, and the code is working fine now thanks