Ember.js router events as functions not working - ember.js

I have set up some basic routing in my app by using the examples at http://emberjs.com/guides/outlets/#toc_the-router
Within the root I have some events that trigger from view actions e.g:
gotoStepOne: Ember.Route.transitionTo('stepOne'),
gotoStepTwo: Ember.Route.transitionTo('stepTwo'),
gotoStepThree: Ember.Route.transitionTo('stepThree'),
gotoStepFour: Ember.Route.transitionTo('stepFour'),
gotoStepFive: Ember.Route.transitionTo('stepFive'),
Full example router code at http://jsfiddle.net/hellosmithy/WdjXT/
This all works fine at the moment. The problem is that I'd like to add other code into these events. For example:
gotoStepOne: function() {
if (someCondition) {
Ember.Route.transitionTo('stepOne');
}
someOtherFunction();
}
However doing this breaks the routing without throwing any errors. It just no longer transitions.
Specifically I only want transitions to happen if a certain state is met - something has been selected or input by the user at each stage before they can proceed. Is there a workaround for this, or should I be abstracting this functionality elsewhere?

The way I understand the router is, that it is the representation of the application's state.
Specifically I only want transitions to happen if a certain state is met - something has been selected or input by the user at each stage before they can proceed.
So the user inputting or selecting something puts your application in a certain state which is reflected by the router.
IMHO it should be something like this in a view (or controller):
userDidSomething: function(condition) {
if (condition) {
App.get('router').send('stepOne');
}else{
someOtherFunction();
}
}

Related

How to detect URL schemes with .handlesExternalEvents and NSAppleEventManager simultaneously

I have a SwiftUI-based Mac app with multiple WindowGroups.
1. Opening different SwiftUI WindowGroups using URL schemes
To open those windows I am using URL schemes (like described here):
WindowGroup {
// ...
}
.handlesExternalEvents(matching: Set(arrayLiteral: "primaryWindow"))
... and then calling:
NSWorkspace.shared.open(URL(string: "myapp://primaryWindow")!)
☑️ This works just fine!
2. Detecting URLs called from outside the app
I also need to be able to recognise and handle URL schemes called from outside the app, like myapp://somePath?someParameter=1. I found this solution and set an event handler within my AppDelegate:
func applicationWillFinishLaunching(_ notification: Notification) {
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(self.handleGetURL(event:reply:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL)) )
}
☑️ This works just fine, too, and my #selector method is called like you would expect.
3. Problem: How to use .handlesExternalEvents and .setEventHandler simultaneously?
🛑 Here’s where the problem starts: After calling .setEventHandler my WindowGroups no longer react on called URLs and I remain unable to open new windows.
That somehow makes sense since I’ve registered an event handler in AppDelegate specifically for kAEGetURL but I have no idea how to implement both features simultaneously. Looking forward for your advice!

Deadlock when dispatching notification in notification handler using Poco::NotificationCenter

I'm using Poco as part of a C++ app and I've run into an issue I don't quite understand. The app was translated from Obj-C and made heavy use of Apple's NSNotificationCenter.
To make the transition as painless as possible, I decided to use Poco's NotificationCenter instead. It works fine but I had some users reporting deadlocks I'm now trying to resolve.
Just a quick heads-up for those not familiar with NotificationCenter. You signup for a notification like this:
Poco::NotificationCenter& nc = Poco::NotificationCenter::defaultCenter();
nc.addObserver(Poco::NObserver<MyClass, MyNotification>(*this, &MyClass::onNotification));
and post a notification like this:
Poco::NotificationCenter& nc = Poco::NotificationCenter::defaultCenter();
nc.postNotification(new MyNotification());
The postNotification() method is defined like this:
void NotificationCenter::postNotification(Notification::Ptr pNotification)
{
poco_check_ptr (pNotification);
ScopedLockWithUnlock<Mutex> lock(_mutex);
ObserverList observersToNotify(_observers);
lock.unlock();
for (ObserverList::iterator it = observersToNotify.begin(); it != observersToNotify.end(); ++it)
{
(*it)->notify(pNotification);
}
}
And NObserver::notify() like this:
void notify(Notification* pNf) const
{
Poco::Mutex::ScopedLock lock(_mutex);
if (_pObject)
{
N* pCastNf = dynamic_cast<N*>(pNf);
if (pCastNf)
{
NotificationPtr ptr(pCastNf, true);
(_pObject->*_method)(ptr);
}
}
}
This is all really simple and doesn't involve any black magic.
Given the fact that the postNotification method always iterates over all observers (AFTER locking one and before checking if the type of the notification matches using a dynamic typecast) I'm assuming that this MUST always cause a deadlock when a notification is sent from a notification handler as it would also try to access the observer where itself is called from and will wait forever on the lock in NObserver::notify()?
From the process samples my users sent me it looks like my assumption is correct.
But for some reason this doesn't appear to deadlock in most cases (I never experienced it ever myself). I just stepped through with the debugger and couldn't make it lock up. Does anyone have an explanation why this only locks up under certain circumstances?

Meteor - Subscription Does not Update Collection Display Until Refresh (Cache in Template?)

I have a template ("ImageView") displaying collection data, and I use it at two different routes to display different content: at one route it is used to display all data, and at another to display data that belongs to specific user.
Because my layout has various components so I embed the ImageView template within the main template of each route ("Album" and "Profile").
I set up the template level subscription at the two main templates like so:
Template.profile.onCreated ( function() {
Tracker.autorun(function() {
Meteor.subscribe('images', Meteor.userId());
});
});
and
Template.Album.onCreated (function() {
Tracker.autorun(function() {
Meteor.subscribe('images');
}); })
and I have my publication function like so at the server:
Meteor.publish('images', function ( user_id) {
findQuery={}
if (user_id) {
findQuery = {userId: user_id};
}
return Images.find(findQuery);
});
The problem is that, when I navigate between the route between the two pages, the template "ImageView" will not update its content reactively, until I press refresh. (If I enter the url by hand and press enter it will also work fine). Are there cache within the template? But they seemed to be created and destroyed as expected when route changes (checked in onCreated and onDestroyed callbacks).
I have console logged inside the publish function and I made sure the publication is changed when I navigate between the two routes, but the client side is not updating accordingly. I have also tried reactive-publish package, Template.subscriptionReady,FlowRouter.reload() and they don't solve the issue.
Can anyone give me insights on what the issue might be? Btw, I am using FlowRouter.
Any inputs are appreciated. Thank you very much.
You shouldn't use Tracker.autorun in onCreated because you would have to stop the computation manually when the template is destroyed. Use this.autorun instead. It uses the Template autorun.

ember-data 2.0 and Offline

I am creating a new ember app. I want to use the newest version of ember-data. (ember-data 2.0). I want it to be a mobile webapp. Therefore it must handle variable network access and even offline.
I want it to store all data locally and use that data when it goes offline so the user gets the same experience regardless of the network connectivity.
Is ember-data 2.0 capable of handling the offline case? Do I just make an adapter that detects offline/online and then do....?
Or do I have to make my own in-between layer to hide the offline handling from ember-data?
Are there any libraries out there that has this problem solved? I have found some, but are there any that is up to date with the latest version of ember-data?
If device will go offline and user will try to transition to route, for which model is not loaded yet, you will have an error. You need to handle these situations yourself. For example, you may create a nice page with error message and a refresh button. To do this, you need:
First, In application route, create error action (it will catch errors during model hook), and when error occurs, save transition in memory. Do not try to use local storage for this task, it will save only properties, while we need an actual transition object. Use either window.failedTransition or inject in controllers and routes a simple object, which will contain a failed transition.
actions: {
error: function (error, transition) {
transition.abort();
/**
* You need to correct this line, as you don't have memoryStorage
* injected. Use window.failedTransition, or create a simple
* storage, Iy's up to you.
*/
this.get('memoryStorage').set('failedTransition', transition);
return true; //This line is important, or the whole idea will not work
}
}
Second, Create an error controller and template. In error controller define an action, retry:
actions: {
retry: function () {
/**
* Correct this line too
*/
var transition = this.get('memoryStorage').getAndRemove('failedTransition');
if (transition !== undefined) {
transition.retry();
}
}
}
Finally, In error template display a status and an error text (if any available) and a button with that action to retry a transition.
This is a simple solution for simple case (device gone offline just for few seconds), maybe you will need something way more complex. If you want your application to fully work without a network access, than you may want to use local storage (there is an addon https://github.com/funkensturm/ember-local-storage) for all data and sync it with server from time to time (i.e sync data every 10 sec in background). Unfortunately I didn't try such things, but I think it is possible.

Undesirable scope bleed between components in Ember

I have a component [ui-button] (github) where I'm adding a wrapping component called ui-buttons (demo here). The problem is that the wrapping component seems to receive registrations not only from its children but from ALL children that are on the page! Effectively this property is acting like a static variable across all instances of ui-buttons. I didn't even know you could do this and in this case its definitely an undesirable effect.
In the demo link above try clicking on the the "disable the group" button and notice that it disables ALL buttons. So what am I doing?
Structurally it looks like this:
{{#ui-buttons as |group|}}
{{ui-radio-button title='foo' group=group}}
{{ui-radio-button title='bar' group=group}}
{{ui-radio-button title='baz' group=group}}
{{/ui-buttons}}
In this process I have child elements (e.g., ui-radio-button) register themselves with ui-buttons. The item-level registration code is:
_registration: on('init', function() {
const group = this.get('group');
if(group) {
group._registerItem(this);
}
}),
and the group-level registration code is:
_registerItem: function(child) {
console.log('registering %o with %o', child, this.get('elementId'), this.get('_registeredItems.length'));
this.get('_registeredItems').pushObject(child);
},
If you note the group-level registration has a "console.log" statement and that produces very encouraging results (it recognizes the element ID of the group as being distinct) alongside worrisome results (the registry "length" continues to grow across all):
I suspect this is down to async or this complexities but I'm now at a loss on how to proceed.
Your problem is this line of code
_registeredItems: new A([]),
That creates a single array one time (I believe when the component is parsed - on application load) and all your components are using it..
Best bet is to change it to
_registeredItems: Ember.computed(function() {
return new A([]);
})
When _registeredItems is first accessed it creates the new array.