Dynamic Getters/Setters with ES6 Classes - dynamic

I've been searching the web and found some solutions but not an easy to implement solution for dynamic setters in an ES6 Class.
What I'd like is to have is a dynamic setter inside my class so that when I add any possible property from the outside, a certain operation will occur on that property. I've read on Proxies and that does seem to be the reasonable solution for this. However, I wasn't able to understand how to correctly implement it and would like your guys' input on this.
Thanks!

let property_one = 'one';
let property_two = 'two';
/**
* ConfigurationClass class.
*/
class ConfigurationClass
{
/**
* Constructor.
*
* Create instance.
*/
constructor(config = {
'property_one' : property_one,
'property_two' : property_two,
})
{
this.__proto__ = new Proxy(config, {
get: (container, property) => (property in container) ? container[property] : undefined,
set: (container, property, value) => (container[property] = value) ? true : true
});
}
};
let configurationClass = new ConfigurationClass();
console.log(configurationClass.property_one); // one
console.log(configurationClass.property_two); // two
console.log(configurationClass.property_three); // undefined

Related

Why is the dynamic serialization group I've created not allowing a mutation for the specified property?

I've implemented a Dynamic Serialization group via Context Builder for admin users (adding admin:write). And have assigned this group to the property I want only updatable by an admin via GraphQL.
My implementation at this point is taken directly from https://api-platform.com/docs/core/graphql/#changing-the-serialization-context-dynamically
But when attempting to mutate this property I am given an error that reads Field "roles" is not defined by type updateUserInput.
This makes some sense to me as the schema does not contain this property since it is not in the typical write group. However, the documentation suggests this should be doable. If this is the case, what am I not doing correctly?
Relevant Code:
Context Builder
<?php
namespace App\Serializer;
use ApiPlatform\Core\GraphQl\Serializer\SerializerContextBuilderInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* Context Builder: Experimental implementation used for constructing what resources are returned.
*/
final class AdminGroupsContextBuilder implements SerializerContextBuilderInterface {
private $decorated;
private $authorizationChecker;
/**
*
*/
public function __construct(SerializerContextBuilderInterface $decorated, AuthorizationCheckerInterface $authorizationChecker) {
$this->decorated = $decorated;
$this->authorizationChecker = $authorizationChecker;
}
/**
*
*/
public function create(?string $resourceClass, string $operationName, array $resolverContext, bool $normalization): array {
$context = $this->decorated->create($resourceClass, $operationName, $resolverContext, $normalization);
$resourceClass = $context['resource_class'] ?? NULL;
if (isset($context['groups']) && $this->authorizationChecker->isGranted('ROLE_ADMIN') && FALSE === $normalization) {
$context['groups'][] = 'admin:input';
}
return $context;
}
}
User Entity Class property definition
/**
* #ORM\Column(type="json")
* #Groups({"read", "admin:write"})
*/
private $roles = [];
Services Definition
App\Serializer\AdminGroupsContextBuilder:
decorates: 'api_platform.graphql.serializer.context_builder'
arguments: [ '#App\Serializer\AdminGroupsContextBuilder.inner' ]
autoconfigure: false

How to add additional properties to be passed through sequelize object in express

So for example I have a sequelize model as follows:
// MyModel.js
module.exports = (sequelize, DataTypes) => {
const MyModel = sequelize.define('MyModel',{
foo: DataTypes.STRING,
});
return MyModel
}
And then I use this model to express templating engine using controller as follows:
app.get('/foobar',async function(req,res,next){
var myModel = await MyModel.findById('abcd1234');
myModel.bar = bar
return res.render('foobar',{
myModel: myModel
});
})
and my foobar.pug is like this:
html
#{JSON.stringify(myModel)}
Apparently I can find the field called foo, but I can't get the field called bar, how do I pass this additional calculated field from my controller through my model?
Reason behind this is :
var myModel = await MyModel.findById('abcd1234');
// will return an instance of MyModel not json
// So you can't just do
myModel.bar = bar;
To make it happen ( Convert instance to JSON Object )
var myModel = await MyModel.findById('abcd1234').toJSON();
// Now this will return the JSON object and not instance of MyModel
// Now this will work
myModel.bar = bar;
toJSON() is sequelizejs's model's method , you can convert it via javascript function also.
If you want to retain the sequelize object , retain it in different variable
var myModelInstance = await MyModel.findById('abcd1234');
var myModel = myModelInstance.get({plain: true});
// OR
var myModel = myModelInstance.toJSON();
// Now this will work
myModel.bar = bar;
These are the possible ways of doing , but because of lack of
requirement and code this is the best I can suggest , you can still
look into GETTER , if you need the extra fields inside
instance.
For anyone looking for this in 2K22 and after :D,
you can use DataType.VIRTUAL when registering a field,
this allow predefining additional fields that will be used and keep it at serialize time but not persist into database.

singleton object in react native

I'm new in react native.I want store multiple small small strings to common singleton object class and want to access it from singleton object for all component. Can anyone help me singleton object implementation for react native.
Ex
Component 1 -- Login button -- >> success --> need to store userID into singleton object.
Component 2 --> get stored userID from singleton object. How can i implement it.
Here is a simple way of doing it...
export default class CommonDataManager {
static myInstance = null;
_userID = "";
/**
* #returns {CommonDataManager}
*/
static getInstance() {
if (CommonDataManager.myInstance == null) {
CommonDataManager.myInstance = new CommonDataManager();
}
return this.myInstance;
}
getUserID() {
return this._userID;
}
setUserID(id) {
this._userID = id;
}
}
And here is how to use it...
import CommonDataManager from './CommonDataManager';
// When storing data.
let commonData = CommonDataManager.getInstance();
commonData.setUserID("User1");
// When retrieving stored data.
let commonData = CommonDataManager.getInstance();
let userId = commonData.getUserID();
console.log(userId);
Hope this works out for you :)
I suggest making a static class that stores data using AsyncStorage.
You mentioned in a comment that you are already using AsyncStorage, but don't like spreading this functionality throughout your app. (i.e. try-catches all over the place, each component needing to check if a key is available, etc.) If this functionality were in a single class, it would clean up your code a lot.
Another bonus to this approach is that you could swap out the implementation pretty easily, for example, you could choose to use an in-memory object or AsyncStorage or whatever and you would only have to change this one file
NOTE: AsyncStorage is not a safe way to store sensitive information. See this question for more info on the security of AsyncStorage and alternatives.
That said, this is how I imagine a global data holder class might look:
export default class dataManager {
static storeKeyValue(key, value) {
// your choice of implementation:
// check if key is used
// wrap in try-catch
// etc.
}
static getValueForKey(key) {
// get the value out for the given key
}
// etc...
}
Then to use this class anywhere in your app, just import wherever it's needed like so:
import dataManager from 'path/to/dataManager.js';
// store value
dataManager.storeKeyValue('myKey', 'myValue');
// get value
const storedValue = dataManager.getValueForKey('myKey');
EDIT: Using Flux, Redux, or a similar technology is probably the preferred/suggested way to do this in most cases, but if you feel the Singleton pattern works best for your app then this is a good way to go. See You Might Not Need Redux
There is a workaround for this, react native packager require all the modules in the compilation phase for a generating a bundle , and after first require it generates an internal id for the module, which is from then on referenced in the whole run-time memory , so if we export an instance of a class from the file, that object will be referenced every-time whenever that file is imported .
TLDR;
Solution I :
class abc {
}
module.exports = new abc()
Solution II : I assume you want to get your strings which are static and wont change , so you can declare them as static and access them directly with class name
FYI :this works with webpack also.
I might be too late for this, but I might as well share my own implementation based on Yeshan Jay's answer.
export default class Data {
static instance = null;
_state = {};
static get inst() {
if (Data.instance == null) {
Data.instance = new Data();
}
return this.instance;
}
static get state() {
return Data.inst._state;
}
static set state(state) {
Data.inst._state = state;
}
static setState(state) {
Data.inst._state = {...Data.inst._state, ...state}
}
}
And here's how you use it. It's pretty much mimicking React Component's state behavior, so you should feel at home with little to no adjustment, without the need to frequently modify the Singleton to add new properties now and then.
import Data from './Data'
// change the whole singleton data
Data.state = { userId: "11231244", accessToken: "fa7sd87a8sdf7as" }
// change only a property
Data.setState ({ userId: "1231234" })
// get a single property directly
console.log("User Id: ", Data.state.userId)
// get a single property or more via object deconstruction
const { userId, property } = Data.state
console.log("User Id: ", userId)
TS Class Example:
export class SingletonClass
{
private static _instance: SingletonClass;
public anyMetod(_value:any):any
{
return _value;
}
public static getInstance(): SingletonClass
{
if (SingletonClass._instance == null)
{
SingletonClass._instance = new SingletonClass();
}
return this._instance;
}
constructor()
{
if(SingletonClass._instance)
{
throw new Error("Error: Instantiation failed: Use SingletonClass.getInstance() instead of new.");
}
}
}
Use:
SingletonClass.getInstance().anyMetod(1);

Aurelia DataTables Recompile

I've been exploring Aurelia and so far have loved what I've seen. I've come accross an issue that I'm not really sure how to solve. I used jquery datatables for large results in my current app with angular, using server side fetches. Datatables has a function you can call whenever a new row is added to the table (fnRowCallback - http://legacy.datatables.net/ref#fnRowCallback, or "createdRow" - https://datatables.net/examples/advanced_init/row_callback.html#) - This is really handy as you can recompile the dom after each row (costly I know).
This enables you to reference functions that exist in the current scope (or viewModel) that the datatable exists in. For example:
In my view model:
export class DataTableTest{
test(){
alert('this is a test');
}
}
In the return results from a datatable fetch:
{name:'blah',age:40,actions:"<a click.delegate='test();'>Test</a>"}
For some reason I can't seem to figure out how to recompile an element once it has been added to the dom.
Does anyone have any ideas how you could do this?
UPDATE:
These are the original options I pass to datatables:
var options = {
"fnRowCallback": function (nRow) {
$compile($(nRow).contents())(scope);
}
};
I've tried the following after injecting that compiler service:
"fnRowCallback": function (nRow) {
this.compiler.compile($(nRow).contents()).fragment.innerHTML;
},
But I always get Uncaught TypeError: Cannot read property 'compile' of undefined - I do this in the "attached" function.. If I console.log(this.compiler) outside of these options, it's available. Also, we don't need to return html back to datatables, just run the compile on the contents. Many thanks for all your help!
You can use a compiler service to compile the element:
import {inject, ViewCompiler, ViewResources, Container} from 'aurelia-framework';
/**
* Compiler service
*
* compiles an HTML element with aurelia
*/
#inject(ViewCompiler, ViewResources, Container)
export class Compiler {
viewCompiler: any;
resources: any;
container: any;
constructor(viewCompiler, resources, container) {
this.viewCompiler = viewCompiler;
this.resources = resources;
this.container = container;
}
compile(templateOrFragment, ctx = null, viewSlot = null):any {
if (typeof templateOrFragment === "string") {
var temp = document.createElement('span');
temp.innerHTML = templateOrFragment;
templateOrFragment = temp;
}
var view = this.viewCompiler.compile(templateOrFragment, this.resources).create(this.container, ctx);
return view;
}
}
I use this in Kendo in the cell template callback function (it lets you return a string that will become the cell contents)
function(dataItem) {
var cellctx = { "$item": dataItem, "$parent": ctx };
return this.compiler.compile(templateString, cellctx).fragment.innerHTML;
}
(this happens in Aurelia's bind callback so the ctx is the executionContext)
I just wrap the current data item up in a context and alias it as $item so I can work with it.
Looks something like this:
<kendo-grid>
<kendo-grid-col title="Main Office" field="IsMainOffice">
<kendo-template><img if.bind="$item.IsMainOffice" src="/content/img/accept.png" /></kendo-template>
</kendo-grid-col>
</kendo-grid>

Properties in a module

Is there a way to define a property in a TypeScript module?
None of these compile:
module My {
// doesnt work
get Value(): number { return 42; }
// doesn't work either
get function Value(): number { return 42; }
// nope
function get Value(): number { return 42; }
}
Right now I'm forced to use this:
module My {
declare var Value: number;
Object.defineProperty(My, "Value", {
get: () => 42
});
}
The second form seems messy to me and the code hinting doesn't really treat it as a read-only property but as a plain variable.
Is there any standard way of defining properties directly inside modules?
No, there's not a way to declare a property on a module in TypeScript using any documented language features.
You can do it in several slightly round-about techniques.
A module can extend an existing class or function. So, I've created a class with a static property, and then later created a module that uses the same name as the class.
class My
{
static get Value():Number {
return 42;
}
}
module My {
var works: boolean = true;
}
alert(My.Value);
It does generate one oddity in the JavaScript generated code that you wouldn't do manually (and should be removed by most optimizers anyway) ... it will redeclare the variable My when the module is created. This does not cause a run-time issue as the variable was already lifted in JavaScript and will not conflict with the first usage.
Here's another option:
module Global {
class Inner {
get Value():Number {
return 42;
}
}
export var My;
My = new Inner();
}
var My = Global.My;
alert(My.Value);
While it presents an extra namespace, you can manipulate it however you'd like and use the inner class or change it as needed. This way, the My variable is global, just like it would be as a module.
Instead of using the module keyword, consider instead using export, which will allow you to do what you want to do, treating the file itself as a module (which is how CommonJS and AMD both work).
// in My.ts
var My = {
get value() {
return 42;
}
};
export = My;
// in foo.ts
import My = require('My');
console.log(My.value);
I describe this in greater detail in a blog post, The Definitive Guide to TypeScript.
I tried the singleton
let My = {
get value() {
return 42;
}
}
export My
but ran into an issue where the emitted JS still said get value() and didn't work on older versions of Node. I tried Object.defineProperty but then lost TypeScript compatibility. Here's my bridge that fixes both cases:
interface My {
value: number
}
// type assertion fixes TypeScript usage
let my = <My>{}
// defineProperty fixes JS usage
Object.defineProperty(my, 'value', {
get: () => 42
});
export = my;
It's used like a module in typescript
import * as my from './my'
my.property // returns 42
// my.property = doesn't work
I know it's a "little" late for this but using typescript 4.8 you can do this:
export module MyModule {
export var myVariable: string = "test";
}
then use it like:
MyModule.myVariable = "something else";