Is there a way to get access to Aurelia's Dependency Injection system without constructor injection.
I have a class called Box. I need to know when one of its properties change so I can update my validation. I found that I can use bindingEngine.propertyObserver from this answer.
But my instances of Box are created by BreezeJs, not Aurelia. So using #inject (or #autoinject in my case) to get the instance of bindingEngine is not going to work.
I saw aurelia.container.get will let me resolve from Aurelia's DI framework. But that needs the current instance of the Aurelia object. The only way I can see to get that is... constructor injection!
So, to get around constructor injection, you need... constructor injection!
I hope I am missing something and there is another way to get an instance of bindingEngine without constructor injection.
NOTE: For now I will just convert my variable in to a javascript property and fire an changed event on my own. But I know that this is going to move me to dirty checking... :(
If you want to know when a breeze entity's properties change, use the entityAspect.propertyChanged event:
http://breeze.github.io/doc-js/api-docs/classes/EntityAspect.html#event_propertyChanged
order.entityAspect.propertyChanged.subscribe(
function (propertyChangedArgs) {
// this code will be executed anytime a property value changes on the 'order' entity.
var entity = propertyChangedArgs.entity; // Note: entity === order
var propertyNameChanged = propertyChangedArgs.propertyName;
var oldValue = propertyChangedArgs.oldValue;
var newValue = propertyChangedArgs.newValue;
});
Circumventing constructor injection is not recommended. It violates the dependency inversion principle, however there is a mechanism for doing so:
main.js
export function configure(aurelia) {
aurelia.container.makeGlobal();
...
}
box.js
import {Container} from 'aurelia-dependency-injection';
let bindingEngine = Container.instance.get(BindingEngine);
Related
Is it allowed to store non serializable object in React context ?
I'm unable to find answer on this question in the docs
I know it is considered as a bad practice in redux store, see here.
Could you please provide any arguments or link to the docs about using non serializable objects in context?
Consider next example:
class A {
foo=()=> void 0
bar=()=> void 0
}
const context = React.createContext(new A()) // is this ok ?
I think it is perfectly fine to store non serializable object in React context. And here are some arguments.
First of all, I do not know (correct me if I'm wrong) any internal react mechanics that serializes or unserializes arbitrary context and / or assumes it to be serializable.
Second, react context now is a stable feature (in contrast like it was unstable some time ago). It is unlikely that something will change here, so we do not need to be proactively careful.
Finally, react context is just a way to pass something implicitly deep down into the components tree, not more, not less. React context is actually not about storing something, it is about providing and consuming something. You do not store things in context, you store it somewhere else, maybe in state, maybe somewhere, and then just provide it to consumers. So, why not to provide function to consumers if they need it? How it differs from passing things through props (where passing function is for sure not an antipattern)?
It is more about concrete scenario, and no one knows better then you, how and when to restrict particular context shape. For example, in our project we have some internal redux-like library that synchronizes stores between electron windows via rpc calls. It uses context and we specifically restricted (with typescript) context shape to be serializable (to be able to transfer it via rpc). On the other hand we have many cases where we pass non serializable stuff via context.
I tried using class to solve this problem. The context worked fine.
Sample code:
class Stuff {
data :any = {}
getData() {
return this.data
}
setData(_data) {
this.data = _data
}
}
const StuffInst = new Stuff();
// import this and use where you want
Please comment for suggestions/errors.
In Python3 I can use magic function __new__, which executes before class initialization. This helps me control whether new instance will be created or we will use some instance from cache.
Just a little simplified example:
class Something:
def __new__(..., someArgument):
# was a class with someArgument initialized somewhere before?
# is yes, then:
return CACHE[someArgument]
# if no, then:
CACHE[someArgument] = Something(someArgument)
return CACHE[someArgument]
So, can I the same in ES6? Or how can I control class initializing in other way?
This question is not a duplicate of this one, because I'm asking whether I can find some functionality in JS, while the topic above contains a duscussion about this functionality.
As Justinas commented, you can look up about Javascript Factory.
A Javascript Factory define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Some places you can look it up:
Factory Method Design Pattern
Factory Functions with ES6
Calling Javascript Factory Method
I Hope it helped!
You can use factory function:
class Test {
}
function getInstance() {
if (!Test._instance) {
Test._instance = new Test();
}
return Test._instance;
}
No, when a (non-derived) constructor is invoked with new (or super()) then an object is already instantiated before any custom code runs1. However, JS lets you overwrite the result value of the expression by returning an object from the constructor. You can write
const CACHE = new Map();
class Something {
constructor(someArgument) {
if (CACHE.has(someArgument)) return CACHE.get(someArgument);
// ^^^^^^
CACHE.set(someArgument, this);
// initialise `this`
}
}
That said, a factory function (or even static method) - as suggested by the other answers - is usually a more sensible solution. You'd put the cache handling code only in the constructor if you absolutely needed to enforce this.
1: it could be intercepted by the construct trap of a proxy, but you normally would not use that.
I have a variable that stores the available cars at any moment. Is there a way to automatically re-evaluate this function on every change?
Just using this.carFactory.available in this case is not a solution, because this example I'm showing is simplified - the real calculation in my project is alot more complex.
calculateAvailableCars(){
this.carFactory.available.forEach(function(item){
this.availableCars.push(car.id);
}.bind(this));
}
How could I do this in Angular 2? In Angular JS there was the possibility to $watch a function.
I could of course manually call this function everytime something changes, but it would be nice not to have to call this function in every part of the application that can change the data.
Using template function reference with auto change detection
You can use this function output on template:
carOutput(): cars[] {
this.calculateAvailableCars()
return this.availableCars;
}
and use output on template:
<p>My car ratio is {{ carOutput() }} </p>
However this will trigger very aggressive change detection strategy on this variable. This solution is the simpliest one, but from engineering perspective rather worst: consumes tons of unnecessary function calls. One note, that hosting element must not be set to detect changes onPush.
Separate data model to parent component and pass as property to child
You can store car list display in separate component, and pass new car array as input property to this component:
<car-display [cars]="availableCars"></car-display>
Then you can set changeDetetcion policy in this component to onPush, and each time input property bind to availableCars will change, <car-display> will re-render.
If update relays on some host binding
If some external host action is triggering new cars calculation, then hostBinding may help:
#hostListener(`hover`) recalculateCars() {
this.calculateAvailableCars()
}
And finally, (because you describe your use case quite cryptically, without many details, thus I'm scratching all possible scenarios) if some external component action shall trigger re-calculation, you can hook to ngLifecycle ngOnChanges() if for example external input property change shall re-trigger cars calculation.
In other words and summing all that up, it depends who and from where triggers changes, that shall re-trigger available cars recalculation.
And very important, see an answer from #chiril.sarajiu, because what we are trying to work around here can be handled automatically by single observable. This requires additional setup (service, provide observable to components, e.c.t.) but it's worth.
--- EDIT ---
If each variable change shall retrigger data
As OP clarified, that changes are related with model bound to component. So another option with mentioned by #marvstar is using set, where each model variable change will retrigger fetching function:
modelSchangeSubject: Subject<Model> = new Subject<Model>();
ngOnInitt() {
this.modelSchangeSubject
.subscribe((v: Model) => {
this.calculateAvailableCars()
})
}
/* Rest of controller code */
set modelBounded(v: Model) {
this.modelSchangeSubject.next(v);
}
You need RxJS. What you do is you create a data service, which will store an Observable (in my case a BehaviorSubject, which is mostly the same, but in my case I start with a value).
export class DataService {
private dataStorage$ = new BehaviorSubject(null); //here is the data you start with
get getDataStorage() {
return this.dataStorage$.asObservable(); // so you won't be able to change it outside the service
}
set setDataStorage(data: any) {
this.dataStorage$.next(data);
}
}
Then you subscribe to this data changes everywhere you need to:
constructor(private dataService: DataService){}
ngOnInit() {
this.dataService.getDataStorage.subscribe((data) => this.calculateAvailableCars(data));
}
calculateAvailableCars(){
this.carFactory.available.forEach(function(item){
this.availableCars.push(car.id);
}.bind(this));
}
Read more about best practices of using RxJS in Angular, as there can be quite a bit of pitfalls and problems.
Try using setter and getter.
private _YourVariable:any;
public set YourVariable(value:any){
this._YourVariable = value;
//do your logik stuff here like. calculateAvailableCars
}
public get YourVariable():any{
return this._YourVariable ;
}
I have a js file in my Angular application, data.js . This js file has some variables declared in it, something like below.
var data = 'test'
Now I have to access these variables and their values in my component (app.component.ts).
I read some where that declaring them as exports make them into modules and those can be accessed anywhere, But I'm not sure how this can be done.
This is the structure of my application. I have data.js in assets->js folder.I need to modify the variable value in app.component.ts.
I'm very new to Angular. Is this even possible?
With the file in your assets, I am guessing you are declaring it on the window. You will need the include the script in your index.html, and then access it on the window within your component via window.data. This is not really the recommended way of doing this unless your use case dictates it. The module approach you mentioned is preferred.
Next to your app.component.ts, create a file called data.ts, with:
export let data: string = 'data';
In your app.component.ts, import it using:
import { data } from './data.ts';
If you plan to not mutate that data, consider using the const keyword instead (in data.ts).
Directory structure
/app.component.ts
/data.ts
/...
Edit: Show Global Approach
You will need to include your script outside of the context of the Angular application. If you bootstrapped your application using the Angular CLI, you can add a reference to it in the cli configuration file. See this documentation on the topic.
That file will be included and will be available for access within your component on the window. The tricky part comes with typing and the Window. And example may look like this.
class AppComponent extends Component {
private data: string;
constructor() {
// Explicitly cast window as an any type. Would be better to type this, but this should work for you.
this.data = (<any>window).data;
}
}
(referrring to https://stackoverflow.com/a/42682160)
first you have to include the script into your src/index.html like
< script src="/assets/js/data.js">< /script>
important is that the above statement is placed before your angular root component tags
(< root-component>< /root-component> or < ion-app>< /ion-app> or something like that)
then you can simply write (for example inside app.component.ts ngOnInit function)
let varFromJsFile = window["data"] // varFromJsFile = 'test'
You want the variable to be a member of a Component class, not just a variable declared anywhere within a module.
If this doesn't make sense right away, you need to look more carefully at some basic Angular code samples.
Also, as long as you're using Angular and therefore TypeScript, it's better the declare variables using let or const.
I have a small, home-brewed implementation of the Flux pattern that I'm working with, just to get a better understanding of the pattern. Its working quite well, and I'm learning a ton! But I've run into an issue I can't wrap my head around at the moment. Apologies in advance if this has an obvious solution.
Imagine my simple Store called ExampleStore, and my simple Component ExampleComponent. In it there are:
_exampleState
getExampleState()
setExampleState()
in ExampleComponent, to stay updated:
_onChange: function() {
setState({exampleState: ExampleStore.getExampleState()})
}
in ExampleStore, after a dispatched action I use the setter:
setExampleState(newStateFromDispatchedAction);
This works perfectly. The data is flowing as it should. But I have a question, because it seems easy to break the pattern because there is no privacy enforced on my _exampleState within my Store. Since I have a getter and private setter method for _exampleState, it seems natural to me that somehow I want to enforce more privacy on the variable. Is there a nifty way to do this, that I am overlooking?
As it is now, if, for example, inside ExampleComponent I do (which I wouldn't, but I could):
this.state.exampleState = {field:'example'}
//doing this
this.state.exampleState.field = 'example2';
//changes the store _exampleState to {field:'example2'}
I have changed the value of _exampleState within ExampleStore directly, without making use of the setter. This seems dangerous (and makes me question why I'd have a private setter/public getter to begin with). This question comes after dealing with a pesky bug where a library I was using modified the state variable directly, and thereby within the Store.
Is there some good way I'm overlooking to enforce privacy on the state variables in my Store, so that they may not be changed directly through their references in ExampleComponent? Sorry if this is a dumb question and I'm overlooking something simple, thanks for the help!
Be aware that one of the basic principles of the Flux philosophy is that stores should have no (public) setters. That means you should not be able to modify the store's state if not inside the store itself.
One way of enforcing the privacy could be by keeping state variables as private, only letting the store managing them.
EDIT: to "enforce" privacy, you could also return a deep copy of your state, as it is shown in the code.
The following code, based on the official flux GitHub repository's flux-todomvc example, highlights the idea:
var AppDispatcher = require('../dispatcher/AppDispatcher');
var AppConstants = require('../constants/AppConstants');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
// This is a private state variable that can only be accessed in this file
var _exampleState = {/*...*/};
var ExampleStore = assign({}, EventEmitter.prototype, {
EXAMPLE_STATE_CHANGED: 'EXAMPLE_STATE_CHANGED',
// return a deep copy of your state so there is no way
// to modify the store's state by reference
getExampleState: function() {
return deepCopy(_exampleState);
}
/*...*/
};
// this is a private method (setter)
var _setExampleState = function(newExampleState) {
_exampleState = newExampleState;
};
ExampleStore.dispatchToken = AppDispatcher.register(function(action) {
switch(action.actionType) {
case AppConstants.CHANGE_EXAMPLE_STATE:
_setExampleState(action.newExampleState);
ExampleStore.emit(ExampleStore.EXAMPLE_STATE_CHANGED);
break;
}
});
// the implementation of deepCopy is a developer's choice
// this version of it is very inefficient
var deepCopy = function(obj) {
return JSON.parse(JSON.stringify(obj));
}
module.exports = ExampleStore;
Facebook official examples are a good way to understand how to implement the core Flux concepts.
EDIT: this is a way of "enforcing" privacy of a state variable, but it is discouraged due to the clear loss of efficiency. I guess that the main idea here is that, even though you are able to do so in some situations, changing the store's state through reference is just against Flux. It is important to notice that this enforcement is not a reality in many big libraries. In React, for instance, it is possible to modify the state of a component directly, even though that is completely not recommended.
you can wrap your store in a closure, and provide getters and setters, to prevent accidental modification of your state.
https://facebook.github.io/immutable-js (or Mori or seamless-immutable) provides the means to prevent modifications to nested data, while avoiding the need to make defensive deep clones in your getExampleState method. However, it has a huge impact on your coding style and code base. It possibly works best with a functional coding style, as is encouraged by some flux implementations, like https://github.com/rackt/redux.
Another option is to make it clearer that you don't want the state to be modified by ensuring that non-library code only sees the store state in React 'props', rather than React 'state' - not modifying props should be second nature to a React developer anyway (other bugs will occur if they modify it). This can be done using a generic flux wrapper component, such as Facebook's 'Container' - https://facebook.github.io/flux/docs/flux-utils.html