In the Ember.js app that I'm working on, I want to pass the parameter from template to controller function but can not.
Template
{{#view Ember.Button target="MyApp.Controller" action="start"}}
{{/view}}
Controller
App.MyAppClass = Ember.Controller.extend({
actions: {
start: function(arg) {
console.log(arg);
}
}
});
Are there anyone used to meet this problem?
Are you certain that you are referencing the right controller?
I just did a quick mock test with -
/** templates/foobar.hbs **/
<button {{action "foo" "bar"}}>Foobar</button>
/** controllers/foobar.js **/
var FoobarController = Ember.Controller.extend({
actions: {
foo: function (args) {
alert(args); // getting an alert with "bar"
},
}
});
I suggest reading -
http://emberjs.com/guides/components/sending-actions-from-components-to-your-application/
{{#view Ember.Button target="MyApp.Controller" action="start" param="parameter"}}
{{/view}}
Related
Both functions here return 'undefined'. I can't figure out what's the problem.. It seems so straight-forward??
In the controller I set some properties to present the user with an empty textfield, to ensure they type in their own data.
Amber.ProductController = Ember.ObjectController.extend ({
quantity_property: "",
location_property: "",
employee_name_property: "",
//quantitySubtract: function() {
//return this.get('quantity') -= this.get('quantity_property');
//}.property('quantity', 'quantity_property')
quantitySubtract: Ember.computed('quantity', 'quantity_property', function() {
return this.get('quantity') - this.get('quantity_property');
});
});
Inn the route, both the employeeName and location is being set...
Amber.ProductsUpdateRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', params.product_id);
},
//This defines the actions that we want to expose to the template
actions: {
update: function() {
var product = this.get('currentModel');
var self = this; //ensures access to the transitionTo method inside the success (Promises) function
/* The first parameter to 'then' is the success handler where it transitions
to the list of products, and the second parameter is our failure handler:
A function that does nothing. */
product.set('employeeName', this.get('controller.employee_name_property'))
product.set('location', this.get('controller.location_property'))
product.set('quantity', this.get('controller.quantitySubtract()'))
product.save().then(
function() { self.transitionTo('products') },
function() { }
);
}
}
});
Nothing speciel in the handlebar
<h1>Produkt Forbrug</h1>
<form {{action "update" on="submit"}}>
...
<div>
<label>
Antal<br>
{{input type="text" value=quantity_property}}
</label>
{{#each error in errors.quantity}}
<p class="error">{{error.message}}</p>
{{/each}}
</div>
<button type="update">Save</button>
</form>
get rid of the ()
product.set('quantity', this.get('controller.quantitySubtract'))
And this way was fine:
quantitySubtract: function() {
return this.get('quantity') - this.get('quantity_property');
}.property('quantity', 'quantity_property')
Update:
Seeing your route, that controller wouldn't be applied to that route, it is just using a generic Ember.ObjectController.
Amber.ProductController would go to the Amber.ProductRoute
Amber.ProductUpdateController would go to the Amber.ProductUpdateRoute
If you want to reuse the controller for both routes just extend the product controller like so.
Amber.ProductController = Ember.ObjectController.extend ({
quantity_property: "",
location_property: "",
employee_name_property: "",
quantitySubtract: function() {
return this.get('quantity') - this.get('quantity_property');
}.property('quantity', 'quantity_property')
});
Amber.ProductUpdateController = Amber.ProductController.extend();
I ended up skipping the function and instead do this:
product.set('quantity',
this.get('controller.quantity') - this.get('controller.quantity_property'))
I still dont understand why I could not use that function.. I also tried to rename the controller.. but that was not the issue.. as mentioned before the other two values to fetches to the controller...
Anyways, thanks for trying to help me!
How to iterate over each model value and based on the value update the handlebar UI.
I am using ArrayController. Basically for a particular value in the model I want to change how I display it.
I am not sure what is wrong in the above code. But it does not function as required.
App.SomeStat = Ember.Object.extend({
target: null,
starts: null
}
{{#each stat in controller}}
{{#if isRestricted}} Do something..
{{/if}}
{{/each}}
App.SomestatController = Ember.ArrayController.extend({
isRestricted: function () {
this.forEach(function(target) {
var t= target.get('target');
return t >= MAGIC_NUMBER;
});
}.property('model.#each.target'),
});
You should setup the ArrayController itemController property to an ObjectController which extends the content for each array content.
App.ExtendIndexController = Ember.ObjectController.extend({
isRestricted: Em.computed(function () {
return this.get('name') === 'red';
}).property('name')
});
App.IndexController = Ember.ArrayController.extend({
itemController: 'extendIndex'
});
Then, you could access the added properties in your template when iterating the controller:
{{#each controller}}
<li>{{name}} ({{isRestricted}})</li>
{{/each}}
http://emberjs.jsbin.com/gexos/1/edit
This case is documented in the Ember guide but I think, this specific case should documented as well.
Try this:
App.CensusStat = Ember.Object.extend({
targetPc: null,
starts: null,
isRestricted: function () {
var offTarget = this.get('targetPc');
return (offTarget &&
(Math.abs(offTarget) >=
Ember.I18n.t('ps.label.census.offtarget.restricted.percentage')));
}.property('targetPc')
});
I have DECLARED an emberjs component in template as:
<script type="text/x-handlebars" id="components/custom-component">
<h4>The name of the object passed is : {{object.name}}</h4>
{{#if show_details}}
<p>The details of the object passed are : {{object.details}}</p>
{{/if}}
</script>
Now I am USING this component in my html template as :
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each object in model}}
<li>{{custom-component object=object}}</li>
{{/each}}
</ul>
</script>
My component class for custom-component is as shown below :
App.CustomComponentComponent = Ember.Component.extend({
show_details: function() {
// return true or false based on the OBJECT's property (e.g. "true" if object.type is 'AUTHORIZED')
},
});
Update
The way I achieved it is as follows :
App.CustomComponentComponent = Ember.Component.extend({
show_details: function() {
var object = this.get('object');
if (object.type == "AUTHORIZED")
return true;
else
return false;
}
});
The parameters passed to the component class are available using it's get methods.
It should work this way:
{{custom-component object_name=object}}
(you just used the wrong property name).
This should work if object is the object name. If name is a property of object then use object.name.
UPDATE
This should be straightforward. show_details should be defined as computed property depending on the object type:
App.CustomComponentComponent = Ember.Component.extend({
object: null,
show_details: function() {
var object = this.get('object');
if (object.get('type') === "AUTHORIZED")
return true;
else
return false;
}.property('object.type')
});
or simpler:
App.CustomComponentComponent = Ember.Component.extend({
show_details: function() {
return this.get('object').get('type') === "AUTHORIZED";
}.property('object.type')
});
Don't forget to use get when accessing the properties of an Ember object.
Updated for Glimmer Components
In the newer Ember components (Glimmer), you can access the values passed to the components inside the component class from this.args. The guide here is very helpful.
Simple example from the guide
Before:
import Component from '#ember/component';
import { computed } from '#ember/object';
export default Component.extend({
width: 0,
height: 0,
aspectRatio: computed('width', 'height', function() {
return this.width / this.height;
})
});
{{!-- Usage --}}
<Image #width="1920" #height="1080" />
After:
import Component from '#glimmer/component';
export default class ImageComponent extends Component {
get aspectRatio() {
return this.args.width / this.args.height;
}
}
{{!-- Usage --}}
<Image #width="1920" #height="1080" />
I'm using Ember v1.2.0 along with Handlebars v1.0.0 and jQuery v2.0.2 and I started to use Ember.Component and replace some views I created through components (for example a custom dropdown element) and it felt like the right thing to do, but unfortunately it does not work as I expected.
this is my Handlebars file, placed under `templates/components/my-dropdown:
<div class="dropdown__header" {{action 'toggle'}}>
<i {{bind-attr class=view.iconClass}}></i>{{view.displayText}}
</div>
<div class="dropdown__caret"></div>
<ul class="dropdown__body">
{{yield}}
</ul>
this is the corresponding Ember.Component class:
App.MyDropdownComponent = Ember.Component.extend({
classNames: 'dropdown'.w(),
toggleList: function () {
//var $this = this.$(); // returns null (!!!)
var $this = this.$('.' + this.get('classNames').join(' .')); // returns the expected object
if($this.hasClass('open')) {
$this.removeClass('open');
} else {
$this.addClass('open');
}
// Note: I can't work with classNameBindings and toggleProperty() because the classes
// could also be accessed through other code...
},
click: function (event) {
alert('heureka!'); // never fired!
},
actions: {
toggle: function () {
this.toggleList(); // fired as expected
}
}
});
is this expected behaviour of an Ember.Component?
How can I pass external values into a controller. In the below code I would like to pass in values filtertype and filterterm from PostsController into PostsDynamicController. What is a way do achieve this?
I have a template like this
<script type="text/x-handlebars" id="posts">
{{view Ember.Select
contentBinding="App.names.content"
valueBinding="App.names.selected"
}}
{{view Ember.TextField valueBinding="filterterm" }}
<button {{action "submit"}} > Submit</button>
{{outlet}}
</script>
Part of my App.js is this:
App.PostsController = Ember.ObjectController.extend({
content: [],
filterterm: "",
submit: function () {
var filtertype = App.names.selected;
var filterterm = this.get('filterterm');
this.transitionToRoute("posts.dynamicfinder");
}
});
App.PostsDynamicController = Ember.ObjectController.extend({
init: function () {
//want access to filtertype and filterterm here so that I can pass them in find. i.e.
//App.Request.find(filtertype: filterterm);
this.set('model', App.Request.find(..);
}
});
You cannot pass args to the controller's init() function.
To pass external values into a controller you should use bindings. Specifically the controller's needs property. See the ember guide dependencies-between-controllers
So for example:
// Change handlebars template to valueBinding="filtertype" instead of valueBinding="App.names.selected"
// Also these should be ArrayControllers not ObjectControllers
App.PostsController = Ember.ArrayController.extend({
filterterm: null,
filtertype: null,
submit: function () {
this.transitionToRoute("posts.dynamicfinder");
}
});
App.PostsDynamicController = Ember.ArrayController.extend({
needs: ['posts'],
termBinding: 'controllers.posts.filterterm',
typeBinding: 'controllers.posts.filtertype',
filteredPosts: function() {
var filtertype = this.get('type');
var filterterm = this.get('term');
// ...
}.property('term', 'type')
}
});