getAllComponents and onComponentAdded don't work

why could Flamework's getAllComponents always return empty table and onComponentAdded never work? With any class provided. Even though I'm sure there are some components in the game as I can see them if I print the object that's being returned with Dependency<Components>?
Solution:
Getting id from the generic type and passing it as a component specifier solved the issue ```typescript /** @metadata macro {@link Flamework.resolveDependency intrinsic-flamework-rewrite} */ export function useAllComponents<T extends BaseComponent>(id?: IntrinsicSymbolId<T>): T[] {...
Jump to solution
15 Replies
CahwarDev
CahwarDevOP6d ago
No description
CahwarDev
CahwarDevOP6d ago
in this example I'm trying to get all components that extend BaseComponent but basically I've tried it with other classes as well
wAD
wAD6d ago
are u like sure component is being instantiated and started
CahwarDev
CahwarDevOP6d ago
yep, I checked it with prints in onStart and constructor
wAD
wAD6d ago
>if I print the object that's being returned with Dependency<Components> wdym
CahwarDev
CahwarDevOP6d ago
you see "components" field that I create in constructor that's what I mean
wAD
wAD6d ago
okay silly but just to test can u add a print(Dependency<Components>()) in the component onStart and in this onStart just to compare memory address
CahwarDev
CahwarDevOP6d ago
those are same objects
No description
wAD
wAD6d ago
can i see the component
CahwarDev
CahwarDevOP6d ago
import { BaseComponent, Component, Components } from "@flamework/components";
import { getUniqueId } from "shared/utils/functions/get-unique-id";

export interface MergeableButtonAttributes {
mergeableName?: string;
id?: string;
}

@Component({ tag: "MergeableButton" })
export class MergeableButton extends BaseComponent<MergeableButtonAttributes, BasePart> {
constructor(private components: Components) {
super();

this.attributes.id = getUniqueId();

warn(this.components);
}
}
import { BaseComponent, Component, Components } from "@flamework/components";
import { getUniqueId } from "shared/utils/functions/get-unique-id";

export interface MergeableButtonAttributes {
mergeableName?: string;
id?: string;
}

@Component({ tag: "MergeableButton" })
export class MergeableButton extends BaseComponent<MergeableButtonAttributes, BasePart> {
constructor(private components: Components) {
super();

this.attributes.id = getUniqueId();

warn(this.components);
}
}
what's interesting about it is that if you inspect this object you can clearly see there are onComponentAdded listeners. and yet still if I create new instances of the component I'm listening for the listeners won't be called
CahwarDev
CahwarDevOP6d ago
No description
wAD
wAD6d ago
advice find where listeners are calleed in flamework/components place a breakpoint and see what happens
CahwarDev
CahwarDevOP6d ago
yep i'm going try inspecting it, ty but I guess it never gets to calling those listeners should check it alright, I figured out the issue's source. so, to find added signals Flamework indexes componentAddedListeners array with every PolymorphicId of a component which is the component's definition itself and all the interfaces it implements. and my code doesn't work because it listens for components extended from BaseComponent and BaseComponent is for some reason not included in PolymorphicIds lists of components that extend from it I've also encountered the same issue when I created a generic hook to get a state that contains every component of a certain type. And it turns out that when I call the function and provide a type to it (for example, "Button") it uses this ["client/ui/hooks/use-flamework-dependency@useAllComponents.T"] as a polymorphic id in componentAddedListeners list instead of the type I provide to it
CahwarDev
CahwarDevOP6d ago
No description
No description
No description
Solution
CahwarDev
CahwarDev6d ago
Getting id from the generic type and passing it as a component specifier solved the issue
/** @metadata macro {@link Flamework.resolveDependency intrinsic-flamework-rewrite} */
export function useAllComponents<T extends BaseComponent>(id?: IntrinsicSymbolId<T>): T[] {
assert(id, "id must be defined");

const componentDependency = useFlameworkDependency<Components>();

const [components, setComponents] = useState(componentDependency.getAllComponents<T>(id));

useMountEffect(() => {
const addedConnection = componentDependency.onComponentAdded<T>((component) => {
setComponents([...components, component]);
}, id);

warn(componentDependency);

const removedConnection = componentDependency.onComponentRemoved<T>((component) => {
setComponents([...components.filter((value) => value !== component)]);
}, id);

return () => {
addedConnection.Disconnect();
removedConnection.Disconnect();
};
});

return components;
}
/** @metadata macro {@link Flamework.resolveDependency intrinsic-flamework-rewrite} */
export function useAllComponents<T extends BaseComponent>(id?: IntrinsicSymbolId<T>): T[] {
assert(id, "id must be defined");

const componentDependency = useFlameworkDependency<Components>();

const [components, setComponents] = useState(componentDependency.getAllComponents<T>(id));

useMountEffect(() => {
const addedConnection = componentDependency.onComponentAdded<T>((component) => {
setComponents([...components, component]);
}, id);

warn(componentDependency);

const removedConnection = componentDependency.onComponentRemoved<T>((component) => {
setComponents([...components.filter((value) => value !== component)]);
}, id);

return () => {
addedConnection.Disconnect();
removedConnection.Disconnect();
};
});

return components;
}

Did you find this page helpful?