observedAttributes() is not a function - web-component

I have attributes in a JS Custom Element
static get observedAttributes() {
return ['state','color'];
}
How can I get that whole array in the Callback functions of a Custom Element?
this.observedAttributes() is not a function
I must be overlooking something easy...
Update after question in comment:
I kept forgetting Getter and Setters
I can now do this in the constructor():
this.constructor.observedAttributes.map(attribute =>
Object.defineProperty(this, attribute, {
get() {
return obj.getAttribute(attribute);
},
set(newValue) {
obj.setAttribute(attribute, newValue);
},
enumerable: true,//default:false
configurable: true // default:false
//writable: true // not valid, since there is a set method!
}));
(don't care about the memory consumption side effects)

observedAttributes is defined as static so it'll be called off of the class, not an instance. observedAttributes is also a getter (get) so you will not execute it with (). If you defined the custom element class as FancyButton you should use FancyButton.observedAttributes.

Related

How to use properly EntityRepository instances?

The documentation stresses that I should use a new EntityManager for each request and there's even a middleware for automatically generating it or alternatively I can use em.fork(). So far so good.
The EntityRepository is a great way to make the code readable. I could not find anything in the documentation about how they relate to EntityManager instances. The express-ts-example-app example uses single instances of repositories and the RequestContext middleware. This suggests that there is some under-the-hood magic that finds the correct EntityManager instances at least with the RequestContext. Is it really so?
Also, if I fork the EM manually can it still find the right one? Consider the following example:
(async () => {
DI.orm = await MikroORM.init();
DI.em = DI.orm.em;
DI.companyRepository = DI.orm.em.getRepository(Company);
DI.invoiceRepository = DI.orm.em.getRepository(Invoice);
...
fetchInvoices(em.fork());
}
async function fetchInvoices(em) {
for (const company of await DI.companyRepository.findAll()) {
fetchInvoicesOfACompany(company, em.fork())
}
}
async function fetchInvoicesOfACompany(company, em) {
let done = false;
while (!done) {
const invoice = await getNextInvoice(company.taxnumber, company.lastInvoice);
if ( invoice ) {
DI.invoiceRepository.persist(invoice);
company.lastInvoice = invoice.id;
em.flush();
} else {
done = true;
}
}
}
Does the DI.invoiceRepository.persist() in fetchInvoicesOfACompany() use the right EM instance? If not, what should I do?
Also, if I'm not mistaken, the em.flush() in fetchInvoicesOfACompany() does not update company, since that belongs to another EM - how should I handle situations like this?
First of all, repository is just a thin layer on top of EM (an extension point if you want), that bares the entity name so you don't have to pass it to the first parameter of EM method (e.g. em.find(Ent, ...) vs repo.find(...).
Then the contexts - you need a dedicated context for each request, so it has its own identity map. If you use RequestContext helper, the context is created and saved via domain API. Thanks to this, all the methods that are executed inside the domain handler will use the right instance automatically - this happens in the em.getContext() method, that first checks the RequestContext helper.
https://mikro-orm.io/docs/identity-map/#requestcontext-helper-for-di-containers
Check the tests for better understanding of how it works:
https://github.com/mikro-orm/mikro-orm/blob/master/tests/RequestContext.test.ts
So if you use repositories, with RequestContext helper it will work just fine as the singleton repository instance will use the singleton EM instance that will then use the right request based instance via em.getContext() where approapriate.
But if you use manual forking instead, you are responsible use the right repository instance - each EM fork will have its own one. So in this case you can't use a singleton, you need to do forkedEm.getRepository(Ent).
Btw alternatively you can also use AsyncLocalStorage which is faster (and not deprecated), if you are on node 12+. The RequestContext helper implementation will use ALS in v5, as node 12+ will be requried.
https://mikro-orm.io/docs/async-local-storage
Another thing you could do is to use the RequestContext helper manually instead of via middlewares - something like the following:
(async () => {
DI.orm = await MikroORM.init();
DI.em = DI.orm.em;
DI.companyRepository = DI.orm.em.getRepository(Company);
DI.invoiceRepository = DI.orm.em.getRepository(Invoice);
...
await RequestContext.createAsync(DI.em, async () => {
await fetchInvoices();
})
});
async function fetchInvoices() {
for (const company of await DI.companyRepository.findAll()) {
await fetchInvoicesOfACompany(company)
}
}
async function fetchInvoicesOfACompany(company) {
let done = false;
while (!done) {
const invoice = await getNextInvoice(company.taxnumber, company.lastInvoice);
if (invoice) {
company.lastInvoice = invoice; // passing entity instance, no need to persist as `company` is managed entity and this change will be cascaded
await DI.em.flush();
} else {
done = true;
}
}
}

How to denormalize an array recursively in Symfony 5?

I am currently trying to denormalize an array, which came out of an API as a JSON response and was JSON decoded.
The problem is, that I want it to be denormalized into a class and one of the properties is another class.
It feels like it should be possible to get such an easy job done with the Symfony denormalizer, but I always get the following exception:
Failed to denormalize attribute "inner_property" value for class "App\Model\Api\Outer": Expected argument of type "App\Model\Api\Inner", "array" given at property path "inner_property".
My denormalizing code looks like that:
$this->denormalizer->denormalize($jsonOuter, Outer::class);
The denormalizer is injected in the constructor:
public function __construct(DenormalizerInterface $denormalizer) {
The array I try to denormalize:
array (
'inner_property' =>
array (
'property' => '12345',
),
)
Finally the both classes I try to denormalize to:
class Outer
{
/** #var InnerProperty */
private $innerProperty;
public function getInnerProperty(): InnerProperty
{
return $this->innerProperty;
}
public function setInnerProperty(InnerProperty $innerProperty): void
{
$this->innerProperty = $innerProperty;
}
}
class InnerProperty
{
private $property;
public function getProperty(): string
{
return $this->property;
}
public function setProperty(string $property): void
{
$this->property = $property;
}
}
After hours of searching I finally found the reason. The problem was the combination of the "inner_property" snake case and $innerProperty or getInnerProperty camel case. In Symfony 5 the camel case to snake case converter is not enabled by default.
So I had to do this by adding this config in the config/packages/framework.yaml:
framework:
serializer:
name_converter: 'serializer.name_converter.camel_case_to_snake_case'
Here is the reference to the Symfony documentation: https://symfony.com/doc/current/serializer.html#enabling-a-name-converter
Alternatively I could have also add a SerializedName annotation to the property in the Outer class:
https://symfony.com/doc/current/components/serializer.html#configure-name-conversion-using-metadata
PS: My question was not asked properly, because I didn't changed the property and class names properly. So I fixed that in the question for future visitors.

How to inject content to Twig generated content?

I would like to inject content to Twig generated content after everything else has been parsed and done.
Right now I'm using this code below:
public function onResponse(KernelEvent $event)
{
// TODO: find a better way to inject
$event->getResponse()->setContent(
$this->asseticProcessor->inject($event->getResponse()->getContent()));
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => array('onResponse', -9999),
);
}
However, I feel like it may not be the optimal way to do so. First of all, at least I want to do the injection only when Twig HTML templates are actually rendered (in some cases, the controller can simply return a response without rendering anything, or they can render json and in such case I don't have to manipulate the content)
Late to the party here, but you could use a kernel event listener for this. For example:
services:
response_modifier:
class: Some\Bundle\Listener\ModifyResponseListener
tags:
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse, priority: -127 }
Set the priority very low so that it fires towards the of the response chain. The listener might work like so:
class ModifyResponseListener
{
public function onKernelResponse(FilterResponseEvent $event)
{
// We probably want to ignore sub-requests
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$content = $response->getContent();
$content = preg_replace('/foo/is', 'bar', $content);
$response->setContent($content);
}
}
The above will replace all occurrences of "foo" with "bar" in the final output.
Note that you might also have to check that the response is not a redirection, ajax, stream or whatever before modifying the content.

Use std::map with pointer

i try to use std::map as property in my class. I use Visual Studio 2012, and my class is like:
public ref class MyClass
{
std::map<std::wstring,MyType> * mpMyMap;
MyClass()
{
mpMyMap = new std::map<std::wstring,MyType>();
}
~MyClass()
{
delete mpMyMap;
}
Get(std::wstring name)
{
return mpMyMap[name];
}
}
At return mpMyMap[name]; I get error, what there is no operator[] for this type. What should I do?
the bracket operator is on the map, not on the pointer of a map...
Try : return (*mpMyMap)[name];
The correct syntax is
MyType Get(std::wstring name)
{
return (*mpMyMap)[name];
}
You could also make the map an instance member instead of a pointer
std::map<std::wstring,MyType> mMyMap;
then your original code in Get would work and you'd get rid of memory management in the constructor and the destructor of MyClass.
Use
return (*mpMyMap)[name];
or
return mpMyMap->operator[]( name );
P.S. What is this
public ref class MyClass
//^^^^^^^^^^
Also, add return type for Get (MyType in your case)
mpMyMap is a pointer (for which I can see no reason), so you need to dereference it:
return (*mpMyMap)[name];
If mpMyMap must be a dynamically allocated remember to delete it in the destructor and either prevent copying of MyClass or implement copy constructor and assignment operator.
Note Get() is missing a return type (which should be either MyType or MyType&). Make the argument to Get() a const std::wstring& to avoid unnecessary copying and const as Get() does not modify it.
Since mpMyMap is pointer first variant is
Get(std::wstring name)
{
return (*mpMyMap)[name];
}
And second
Get(std::wstring name)
{
return mpMyMap->operator[](name);
}
And Get should have return-type.

Strange behavior from getDefinitionByName

I've created a class that loads it's subclasses based on a name passed to it. The function uses getDefinitionByName, gets the class type, and instantiates it, and returns it if the class is a subtype of the class that owns this method. The subtypes are all mxml files that extend the base class, in order to simplify instantiating controls.
However, in the case where I pass it a fully qualified name, it works in my unit tests but fails when I execute it in the context of my application. Is there a gotcha in getDefinitionByName that makes it behave differently in different execution contexts? Is there a simpler way to load classes by their qualified name?
static public function loadDisplay(className:String, extendedClassName:String = null):FeatureDisplay
{
try
{
trace("Loading", className);
var cls:Class = getDefinitionByName(className) as Class;
var display:FeatureDisplay = new cls() as FeatureDisplay;
if(display)
{
return display;
}
else
{
trace(className, "is not a subclass of FeatureDisplay");
return null;
}
}
catch(error:Error)
{
trace("Error loading", className);
trace("Error:", error.message);
}
return null;
}
My first question is are you explicitly using any of the classes anywhere? If you do not actually use a class, even if it is imported, ActionScript may not end up keeping a copy of the class's definition in the swf.
That said, you're better off avoiding getDefinitionByName, describeType, getQualifiedClassName or getQualifiedSuperclassName if you can possibly avoid them. They are memory hogs and it is generally best to avoid them. (unless you do not have control over which classes will be used at run time and they HAVE to be used through getDefinitionByName).
My suggestion is that you replace getQualifiedClassName with a swtich...case:
// Import the subclasses.
import path.to.SpriteFeatureDisplay;
import path.to.OtherFeatureDisplay;
class FeatureDisplay extends Sprite{
//Make one public static const per class.
public static const SPRITE_FEATURE_DISPLAY:String = "sprite_feature_display";
public static const OTHER_FEATURE_DISPLAY:String = "other_feature_display";
public static function loadDisplay( className:String,
extName:String = null ):FeatureDisplay
{
trace("Loading", className);
// This will ensure that each of the classes is stored in the swf
// it will behave faster, and it is less prone to errors (note that
// try...catch is not needed).
swtich( className )
{
case SPRITE_FEATURE_DISPLAY:
return new SpriteFeatureDisplay();
case OTHER_FEATURE_DISPLAY:
return new OtherFeatureDisplay();
default:
trace( "Requested class " + className + " could not be created..." +
"\nPlease make sure that it is a subclass of FeatureDisplay" );
return null;
}
return null;
}
}
FYI, I've seen the following method of keeping classes used in Flex's source code:
// References.cs
// notice the double reference: one to import, the other to reference
import package.to.ClassA; ClassA;
import package.to.ClassB; ClassB;
import package.to.ClassC; ClassC;
Of course, you still have to reference the "References" class somewhere.

Resources