Ember custom view exception: had no action handler for: searchEvent - ember.js

I have my custom view :
export default Ember.ContainerView.extend({
classNames: ['search-terms'],
eventTypeValue: null,
userSidValue: null,
init: function() {
this._super();
this.eventTypeValue = Ember.TextField.create();
this.userSidValue = Ember.TextField.create();
this.eventTypeValue.set("placeholder", "search by event type");
this.eventTypeValue.addObserver("value", this.userSidValue, this.change);
this.userSidValue.set("placeholder", "earch by user sid");
this.userSidValue.addObserver("value", this.userSidValue, this.change);
this.pushObject(this.eventTypeValue);
this.pushObject(this.userSidValue);
},
change: function() {
this.get("controller").send("searchEvent");
}
});
And controller :
export default Em.Controller.extend({
actions: {
searchEvent : function() {
console.log("controller searchEvent");
}
}
});
And when I change text in some fields, then I have following exception:
Uncaught Error: had no action handler for: searchEvent
But this working when I type some text and then click somewhere out of my custom view.

Your problem is the second argument to addObserver - this is the context that the third argument (this.change) is executed with.
Even though you specify this.change it doesn't use this - it uses the Ember.TextField as the this not the ContainerView.
You need to change the following two lines:
this.eventTypeValue.addObserver("value", this.userSidValue, this.change);
this.userSidValue.addObserver("value", this.userSidValue, this.change);
to:
this.eventTypeValue.addObserver("value", this, this.change);
this.userSidValue.addObserver("value", this, this.change);
This is a working JSBin example
I've commonly seen strings passed as the method (the third argument) - this also works. I would pass strings instead of the actual function itself.
this.eventTypeValue.addObserver("value", this, 'change');
this.userSidValue.addObserver("value", this, 'change');

Related

this.transitionToRoute not working in my controller Ember

I am using a controller to read the value selected on a drop down menu, take in parameters of some input fields and then save the record. It creates the record and takes in the information just fine. My problem lies when I try to transition to another page at the end of the action. I keep getting the error: Cannot read property 'transitionToRoute' of undefined
I am completely stumped. Any ideas?
Here is my controller code:
var teamId;
export default Ember.Controller.extend({
auth: Ember.inject.service(),
actions: {
onSelectEntityType: function(value) {
console.log(value);
teamId = value;
return value;
},
createProcess: function(processName, processDescription) {
var currentID = this.get('auth').getCurrentUser();
let team = this.get('store').peekRecord('team', teamId);
let user = this.get('store').peekRecord('user', currentID);
let process = this.get('store').createRecord('process', {
team: team,
user: user,
name: processName,
description: processDescription
});
process.save().then(function () {
this.transitionToRoute('teams', teamId);
});
}
}
});
Here is the corresponding route:
export default Ember.Route.extend({
auth: Ember.inject.service(),
model: function() {
var currentID = this.get('auth').getCurrentUser();
return this.store.find('user', currentID);
}
});
You should have clear understanding about this keyword in Javascript. The keyword this only depends on how the function was called, not how/when/where it was defined.
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Have a look at the MDN documentation to learn more.
You can cache the this in normal variable this and then access inside the call back.
var self = this;
process.save().then(function () {
self.transitionToRoute('teams', teamId);
});
ECMASCript 6 introduced arrow functions whose this is lexically scoped. Here, this is looked up in scope just like a normal variable.
process.save().then(() => {
this.transitionToRoute('teams', teamId);
});

Compare two Ember objects (created with Ember.Object.create method)

I created a custom object with the Comparable mixin and added it to a model as an attribute with Ember transforms
var customObject = Ember.Object.extend(Ember.Comparable, {
compare: function() {
debugger;
}
});
Once the model is ready I create a copy of the custom object and add it as an attribute to the so that I can compare the custom object when it changes to this original value
export default DS.Model.extend({
custom: DS.attr("custom-object"),
ready: function() {
this.set("originalCustom", Ember.Object.create(this.get("custom")));
},
isUpdated: function() {
return Ember.compare(this.get("custom"), this.get("originalCustom"));
}
});
I manually call isUpdated to check if the compare method is invoked, but it never gets hit.
What am I missing here?

Teach me how to design a nested computed property in ember.js

I have a handful of computed properties defined on a component. I'd like to refactor these computed properties to live within a messages object on the component. When I make a call to get one of the computed properties elsewhere, I'm returned an instance of Ember's ComputedProperty object, rather then the translation string I expected. Looking at the documentation, Ember.get should invoke the computed property and return the object itself, the property value or null.
What am I missing? How would I go about structuring these nested computed properties so that I can access them using the get/set interface elsewhere in the component?
App.ValidatedDateComponent = Ember.Component.extend({
format: null,
label: null,
messages: {
invalidDateMsg: (function() {
return I18n.t('%{date} must be a valid date. %{format}', {
date: this.get('label'),
format: this.get('format')
});
}).property('label', 'format')
},
validate: function(value, status) {
if (!moment(value).isValid()) {
return status(false, Ember.get(this.messages, 'invalidDateMsg'));
} else {
return this._super(value, status);
}
}
});
Ember only supports defining computed properties while extending Ember.Object class, the exception to the rule is while defining a Ember.Mixin.
Defining the top level of the nest
var nest = Ember.Object.extend({
foo: function() {
return "something";
}.property()
});
Creating an instance of it
App.IndexController = Em.ArrayController.extend({
messages: nest.create()
});
Template
{{messages.foo}}
http://emberjs.jsbin.com/UhUvOvU/1/edit
So in your case you could, if you really wanted to, do:
messages: Em.Object.extend({
invalidDateMsg: function() {
return I18n.t('%{date} must be a valid date. %{format}', {
date: this.get('label'),
format: this.get('format')
});
}.property('label', 'format')
}).create(),

Dynamic computed properties in Ember.JS deprecated?

I am trying to make an ember application. I have a computed property and the controller looks like this:
// The Controller
Todos.Controller = Ember.Controller.create({
// ** SNIP ** //
countCompleted: function()
{
return this.get('todos').filterProperty('completed', true).length
}.property(),
});
// The View
{{Todos.Controller.countCompleted.property}} Items Left
Now the tutorial I'm following is using an older version of Ember.JS. I've fixed every error but this:
Uncaught Error: assertion failed: Ember.Object.create no longer supports defining computed properties.
What's the alternative way to do this?
The computed property is only deprecated on the create() function of an object. If you wish to create a computed property, then you must first extend() the object, and then create() it.
For example:
// The Controller
Todos.TodosController = Ember.Controller.extend({
// ** SNIP ** //
countCompleted: function()
{
return this.get('todos').filterProperty('completed', true).length
}.property(),
});
// Note the lower case 't' here. We've made a new object
Todos.todosController = Todos.TodosController.create();
// The View
// We reference the created object here (note the lower case 't' in 'todosController')
{{Todos.todosController .countCompleted.property}} Items Left
It also seems to work ok if you do a reopen:
Todos.todosController = Ember.Controller.create({
// ** SNIP ** //
});
Todos.todosController.reopen({
countCompleted: function() {
return this.get('todos').filterProperty('completed', true).length
}.property(),
});

Easy way to get a reference to the root container view in a deeply nested views

Is there an easy way to access to the root view from a deeply nested child view in an Ember.ContainerView. I'd like to bind a property of the root and a subsubchild :
Ember.ContainerView.create {
childViews: ['child1']
value: null
child1: Ember.ContainerView.create {
childViews: ['subchild1']
subchild1 : Ember.View.create {
valueBinding: "parentView.parentView.value"
}
}
}
I'd like to bind value in the root with value in subchild1 but I found that calling
parentView.parentView.parentView.property
is not very elegant.
You can use the nearestWithProperty method. See the following for an example.
Ember.ContainerView.create({
childViews: ['child1'],
value: null,
isRootView: true,
child1: Ember.ContainerView.extend({
childViews: ['subchild1'],
subchild1 : Ember.View.extend({
rootView: Ember.computed(function() {
return this.nearestWithProperty('isRootView');
}).property().cacheable(),
valueBinding: "rootView.value"
})
})
});
There is no rootView property mentioned in the API docs. What if value was defined in child1? You would still have the same problem of having to reference parentView.value. value should actually be defined in a controller and your subchild1 valueBinding should bind to the property in the controller.