Emberjs Object avoid switch case method hash - ember.js

I have an Ember object that has several actions :
MyObject = Ember.Object.extend {
action1: ->
console.log "do 1"
action2: ->
console.log "do 2"
}
I'd like to call one of these action depending on some condition. The easy way is
to check for this condition and call the needed condition using if or switch-case. But, I need something more scalable like a hash of method inside my object and invoke the needed method by just sending their name like object.exec('action1').
Does ember object has already this feature ?

Here's a quick implementation of a dynamic methods' call method in javascript.
var obj = {
action1 : function(item) {
return item;
},
action2 : function(item) {
return item;
},
exec:function(name){
if(this[name] ==== 'undefined') return;
var args = Array.prototype.slice.call(arguments);
return this[name](args.slice(1,args.length))
}
}
obj.exec('action1','Hello')
obj.exec('action2','World')
Should return Hello World

Related

The method 'add' can't be unconditionally invoked because the receiver can be 'null'. Using for in loop to get a list of data. Flutter

I'm new to programming and I'm learning flutter.
I'm trying to loop through a list of _tasks to get the tasks that has the parentId I need.
Error: The method 'add' can't be unconditionally invoked because the receiver can be 'null'.
Question 1: I already make sure the item is not null in the if statement, but the add method still think the item could be null.. How do I prevent this?
Question 2: If there a better way to get a list of Tasks without using for in loop?
class TaskData extends ChangeNotifier {
List<Task> _tasks = [
Task(parentId: 1, name: "Task1"),
Task(parentId: 1, name: "Task2"),
Task(parentId: 2, name: "Task3"),
Task(parentId: 3, name: "Task3"),
];
List<Task>? getTasksByParentId(int parentId) {
List<Task>? TasksWithSameListId;
if (_tasks.isNotEmpty) {
for (var item in _tasks) {
if (item.parentId == parentId) {
TasksWithSameListId.add(item);
}
}
}
}
Expecting result: when calling function getTasksByParentId, it should return a list of Tasks that has the same parentId.
The error occurs because your variable TasksWithSameListId is nullable. Also never initialized. To fix your issue you can initialize it and make it non nullable.
List<Task> getTasksByParentId(int parentId) {
final List<Task> tasksWithSameId = [];
if (_tasks.isNotEmpty) {
for (var item in _tasks) {
if (item.parentId == parentId) {
tasksWithSameId.add(item);
}
}
}
return tasksWithSameId;
}
A better approach is to use where to filter your list.
List<Task> getTasksByParentId(int parentId) {
return _tasks.where((item) => item.parentId == parentId).toList();
}

Ember - Within action, result is defined, returnvalue of same action logged in parent action is undefined? Why?

Quick and shortly I have following problem:
I have following two actions within a component in Ember:
createData: function(user) {
let collection = [];
for (let i = 0; i < user.posts.length; i++) {
let data = this.send('createSingleData',user.posts[i], user, 'post');
console.log(data);
collection.push(data);
}
return collection;
},
createSingleData: function(data, user, type) {
let entitySkeleton = {
name: data.place.name,
belongsTo: user.id,
position: {
data.place.location.longitude,
data.place.location.latitude
}
};
console.log(entitySkeleton);
return entitySkeleton;
}
the first log - within createSingleData, right before returning the logged value - writes the entitySkeleton as Object into the console - as expected.
However, the console.log(data) - within createData - writes 'undefined' to the console.
Is there any aspect of asynchrounosity I didn't respect?
P.S.:
I also logged any paramater within createSingleData, they are all set properly.
The variable collection also only gets pushed 'undefined'.
You cannot return the value from action, instead you can set property from the action.
how to return values from actions in emberjs
actions: {
PrintSomething: function() {
let obj = [{a: 'raj'}, {a: 'Prudvi'}, {a : 'thimappa'}]
console.log('before', obj);
this.send('returnSomething', obj);
console.log('after calling action', this.get('returnvalue'));
},
returnSomething: function(obj) {
obj.push({a: 'FSDFSDF'})
var data = obj;
this.set('returnvalue', data);
}
}

Return from a beforeRemote

I have two questions regarding "beforeRemote" method of loopback-
How do I get hold of model methods inside beforeRemote method? I mean inside beforeRemote I want to invoke (lets say) "upsert" method of the model.
How do I return invocation from beforeRemote? By return I mean instead of hitting the target invoked method the execution will return from beforeRemote method.
My code -
Installation.beforeRemote("create", function (context, result, next) {
var data = context.req.body;
console.log("ImEI" + data.imei);
data.vendor = "jahid";
var self = this;
var filter = {where: {imei: data.imei}};
//the self here point to global object. but i want self to point to model
self.findOne(filter, function (err, result) {
if (result) {
data.id = result.id;
self.upsert(data, function(err, result){
if(err){
next(err);
} else if(result) {
//here i want to send a valid response back to client with 200 and body as my model.
next(data);
}
});
return;
}
next();
});
});
You have access to the Installation model from the module.exports declaration:
module.exports = function(Installation) {
...
Installation.upsert...
...
}
You have access to the response object from the context object. So you could just respond with something like context.res.send('hello world') and not call next().

Ember not updating query parameters when calling transitionToRoute() right after

In my application, I have an overall controller that manages state for a portion of the application, called SimpleSearch.
Within SimpleSearch, I have multiple SimpleSearchOptions, that display a list of choices to a user.
A user can select an option, and that selection is an action that is called from the view, that bubbles up to the SimpleSearchOptionController:
App.SimpleSearchOptionController = Ember.ObjectController.extend({
//....
select: function (option) {
option.queryName = this.get('queryName');
this.get('simpleSearch').setSelection(option);
this.set('selectedOption', option);
this.set('hasSelectedOption', true);
this.send('transitionToNextOption');
},
//....
This action calls this.get('simpleSearch').setSelection(option);, which registers the selection with the SimpleSearchController:
App.SimpleSearchController = Ember.ObjectController.extend({
//....
setSelection: function (option) {
this.set(option.queryName, option.value);
this.get('selectedOptions').set(option.queryName, option.value);
this.get('model').notifyPropertyChange('selectedOptions');
this.checkIfAllOptionsSelected();
},
//....
The important line in there is: this.set(option.queryName, option.value);.
After it registers the selection, it moves to the next option, and if there isn't one, it skips to the results of the search. That is called from this.send('transitionToNextOption');
App.SimpleSearchOptionController = Ember.ObjectController.extend({
//....
transitionToNextOption: function () {
var nextOptionId = parseInt(this.get("id")) + 1;
var numOfOptions = this.get('simpleSearch.numOfOptions');
if (nextOptionId < numOfOptions) {
this.transitionToRoute('simpleSearchOption', nextOptionId);
}
else {
this.transitionToRoute('simpleSearchResults');
}
},
//....
In setSelection() above, the line this.set(option.queryName, option.value); is setting a query parameter's value. This only works correctly, and the url gets updated accordingly for all options, when I'm not transitioning to a different route.
If I comment out the lines:
else {
this.transitionToRoute('simpleSearchResults');
}
Setting the property (this.set(option.queryName, option.value);) actually has the side effect of Ember updating the query parameter in the URL, which is my intent. If I include that line, and transition to a different route after setting that variable, the query parameter is not updated.
I was stepping through Ember's code, but I can't quite follow how it handles this. It continues into _doTransition(), and I've noticed that the transition to the route 'simpleSearchResults' always happens before the queryParams are passed through.
How do I get Ember to update the query parameter before it transitions to 'simpleSearchResults'?
Thank you for any and all help.
I solved my issue by wrapping the transition in an Ember.run.next() function:
transitionToNextOption: function () {
var nextOptionId = parseInt(this.get("id")) + 1;
var numOfOptions = this.get('simpleSearch.numOfOptions');
if (nextOptionId < numOfOptions) {
this.transitionToRoute('simpleSearchOption', nextOptionId);
}
else {
var self = this;
Ember.run.next(function() { self.transitionToRoute('simpleSearchResults'); });
}
},
I'm assuming, but have not verified, that Ember was queuing up the action to transition to 'simpleSearchResults', and handles the query parameters similarly. Perhaps the transition to a different route was somehow interrupting or overwriting the query parameter being written to the URL.

How can I simulate blur when testing directives in angularjs?

The problem
I am trying to test some directives (code for both below). One of them is an "email" (called "epost" in the code(norwegian)) directive. The solution to this should work for all of them, so I am keeping it to this one for now.
Technologies: Angularjs, Jasmine, Requirejs, (grunt & karma running in Chrome)
The directive validates email addresses in two ways; on upshift and on blur. I can test the upshift without problems as you can see in the test below, but I can't figure out how to simulate a blur so the bind('blur') in the directive runs.
What I have done
I have tried to catch the compiled element like this:
elem = angular.element(html);
element = $compile(elem)($scope);
And then in the test i tried several permutations to trigger the blur with a console log just inside the bind function in the directive. None of the below works. It does not trigger.
elem.trigger('blur');
element.trigger('blur');
elem.triggerHandler('blur');
element.triggerHandler('blur');
element.blur();
elem.blur();
I based the injection and setup on this: To test a custom validation angularjs directive
The email directive in angularjs wrapped in requirejs
define(function() {
var Directive = function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
var pattern = /^[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;
elem.bind('blur', function() {
scope.$apply(function () {
if (!elem.val() || pattern.test(elem.val())) {
ctrl.$setValidity('epost', true);
} else {
ctrl.$setValidity('epost', false);
}
});
});
ctrl.$parsers.unshift(function(viewValue) {
if (pattern.test(viewValue)) {
ctrl.$setValidity('epost', true);
return viewValue;
} else {
return undefined;
}
});
}
};
};
return Directive;
});
The test (using jasmine and requirejs)
define([
'Angular',
'AngularMocks',
], function () {
describe('Directives', function () {
var $scope;
var form;
beforeEach(module('common'));
beforeEach(function () {
var html = '<form name="form">';
html += '<input type="text" id="epost" name="epost" epost="" ng-model="model.epost"/>';
html += '</form>';
inject(function ($compile, $rootScope) {
$scope = $rootScope.$new();
$scope.model = {
epost: null
};
// Compile the element, run digest cycle
var elem = angular.element(html);
$compile(elem)($scope);
$scope.$digest();
form = $scope.form;
});
});
describe('(epost) Given an input field hooked up with the email directive', function () {
var validEmail = 'a#b.no';
var invalidEmail = 'asdf#asdf';
it('should bind data to model and be valid when email is valid on upshift', function () {
form.epost.$setViewValue(validEmail);
expect($scope.model.epost).toBe(validEmail);
expect(form.epost.$valid).toBe(true);
});
});
});
});
I have been able to figure out where I went wrong after some breakpoint debugging.
The "element" item I get out using the approach described in the top of the question is not actually the directive it self. It's an object which wraps the form and the directive.
Like this
{ 0: // The form
{ 0: // The directive (input element)
{
}
}
}
To actually simulate a blur on the directive it self, I did something like this
var directiveElement = $(element[0][0]);
directiveElement.blur();
After getting the element I wanted, and wrapping it in a jQuery object (may be optional), it worked like a charm. I then used the approach like in the test in the question with $setViewValue and checked the model value like this.
form.epost.$setViewValue('a#b.no');
directiveElement.blur();
expect($scope.model.epost).toBe('a#b.no');
expect($scope.form.epost.$valid).toBeTruthy();
Hope this could be of help to others trying to figure the directive testing out.
I too ran into a similar problem and it mystified me. My solution was to use JQuery to get the input and then use angular.element(input).triggerHandler('blur') to make it work. This is odd to me because I do not have to do this with the click event.
spyOn(controller, 'setRevenueIsInvalid');
var sugarRow = $(element).find('tr#ve_id_5')[0];
var amount = $(sugarRow).find('input.amount')[0];
angular.element(amount).triggerHandler('blur');
expect(controller.setRevenueIsInvalid).toHaveBeenCalled();