i’am trying to link hight of a node with another one and having an option to delete that link and that needs the use of figma.on documentchange but the problem is when deleting the handler by figma.off it dosen’t work i have created an if statement to know the deleting message that have been sent when delete button pressed by adding an id wich is 2
if (pluginMessage.id === 'link-it') {
const lnode = figma.getNodeById(pluginMessage.nodeid);
const node = figma.getNodeById(pluginMessage.keysids);
const id = node?.id as string + lnode?.id as string
let fn = (event: { documentChanges: any; }) =>{
for (const change of event.documentChanges) {
if (change.type === 'PROPERTY_CHANGE') {
if (change.id === node?.id) {
lnode.resize(lnode.width, node.height)
}
}
}
}
if (pluginMessage.subid !== 2) {
//add links into the storage
figma.clientStorage.setAsync(id,{subid:'linked',node:node?.id as string,link:lnode?.id});
//do the height changes in figma and post message of the id of nodes to the frontend to put the new links
lnode.resize(lnode.width, node.height)
figma.ui.postMessage({node:node?.id, link:lnode?.id, id:'storageadd',subid:'link'})
//if node height changes change it in the linked node
figma.on('documentchange', fn)
}
else if (pluginMessage.subid === 2) {
figma.clientStorage.deleteAsync(pluginMessage.delnode)
figma.off('documentchange', fn)
}
}
The reason this isn’t working is because fn
is defined as a new function every time you are checking the message. The way figma.on
and figma.off
works is by comparing the values of the supplied functions, which are compared by reference, so creating a new function every time means the function supplied to the on
callback and the function supplied to the off
callback will never be the same.
do you have any idea to fix this because i have those node and lnode variables that needs to be in the fn function which are created by the message
You are going to want to keep track of the ids outside of your onmessage
function, and define your documentchange
function outside of the onmessage
function as well.
Here is a very rough example of how I would watch for property changes on nodes, then react to those changes. You will need to modify it to work for your needs, but I’ve left some comments so hopefully you can figure out how to move forward:
// create an array of node ids to watch for changes
let watchedNodeIds: string[] = []
// create the documentchange handler
const onDocumentChange = event => {
for (const change of event.documentChanges) {
if (change.type === 'PROPERTY_CHANGE') {
// check the array to see if the changed node id matches an id in the list of ids you are keeping track of
const watchedId = watchedNodeIds.find(id => id === change.id)
// if there is a match, get the changed node and do whatever you need to do with it
if (watchedId) {
// do stuff with the node
const node = figma.getNodeById(watchedId)
node.resize(500, 500)
node.getPluginData('foo')
node.remove()
}
}
}
}
// create a variable to keep track of whether the documentchange handler is listening for changes or not
let isWatching = false
// our onmessage handler is now _only_ responsible for adding/removing ids to the array we defined above, as well as attaching/removing our documentchange handler when necessary
figma.ui.onmessage = (message: { type: 'watch' | 'unwatch', nodeId: string }) => {
if (message.type === 'watch') {
// add node id to the array if watching for changes
watchedNodeIds.push(message.nodeId)
} else {
// remove node id to the array if no longer watching
watchedNodeIds = watchedNodeIds.filter(id => id !== message.nodeId)
}
// add the event handler if there are ids that need to be watched and we are not actively listening
if (watchedNodeIds.length > 0 && !isWatching) {
figma.on('documentchange', onDocumentChange)
// update isWatching to true since we are now watching for changes
isWatching = true
return
}
// remove the event handler if there are no ids being watched
if (watchedNodeIds.length === 0 && isWatching) {
figma.off('documentchange', onDocumentChange)
// update isWatching to false since we are no longer watching for changes
isWatching = false
}
}
I don’t think I can provide much more technical help outside of this, but good luck!
hello i have done some changes on that but it looks like it is the same as before i let the function outside on message (btw there is other messages that is why i added new types) but it doesn’t work also the is watching variable isn’t working properly sometimes it does sometimes no if you have time take a look at it and let me know if there is a problem
// create an array of node ids to watch for changes
let watchedNodeIds: string[] = []
let watchedlinkedNodeIds: string[] = []
// create the documentchange handler
const onDocumentChange = event => {
for (const change of event.documentChanges) {
if (change.type === 'PROPERTY_CHANGE') {
// check the array to see if the changed node id matches an id in the list of ids you are keeping track of
const watchedNId = watchedNodeIds.find(id => id === change.id)
// if there is a match, get the changed node and do whatever you need to do with it
if (watchedNId) {
// do stuff with the node
const lnode = figma.getNodeById(watchedlinkedNodeIds[0])
const node = figma.getNodeById(watchedNId)
lnode.resize(lnode.width, node.height)
}
}
}
}
// create a variable to keep track of whether the documentchange handler is listening for changes or not
let isWatching = false
figma.ui.onmessage = (pluginMessage: {selid:string, key:string, height:string|number, id: 'adding'}|{ type: 'watch' | 'unwatch', nodeId: string, lnknodeID: string, id: 'link-it' } | {delnodeId: string ,id: 'delete'}) => {
//when the add button pressed message see if it is in the stored keys or no
if (pluginMessage.id === 'link-it') {
console.log(pluginMessage);
console.log(pluginMessage.nodeId);
// our onmessage handler is now _only_ responsible for adding/removing ids to the array we defined above, as well as attaching/removing our documentchange handler when necessary
if (pluginMessage.type === 'watch') {
// add node id to the array if watching for changes
watchedNodeIds.push(pluginMessage.nodeId)
watchedlinkedNodeIds.push(pluginMessage.lnknodeID)
} else {
// remove node id to the array if no longer watching
console.log(watchedNodeIds);
watchedNodeIds = watchedNodeIds.filter(id => id !== pluginMessage.nodeId)
console.log(watchedNodeIds.length);
}
// add the event handler if there are ids that need to be watched and we are not actively listening
if (watchedNodeIds.length > 0 && isWatching) {
console.log('handler on');
const lnode = figma.getNodeById(watchedlinkedNodeIds[0])
const node = figma.getNodeById(watchedNodeIds[0])
const id = node?.id as string + lnode?.id as string
figma.ui.postMessage({node:node?.id, link:lnode?.id, id:'storageadd',subid:'link'})
figma.clientStorage.setAsync(id,{subid:'linked',node:node?.id as string,link:lnode?.id});
//do the height changes in figma and post message of the id of nodes to the frontend to put the new links
lnode.resize(lnode.width, node.height)
figma.on('documentchange', onDocumentChange)
// update isWatching to true since we are now watching for changes
isWatching = true
}
// remove the event handler if there are no ids being watched
if (watchedNodeIds.length === 0 && !isWatching) {
console.log('handler off');
figma.clientStorage.deleteAsync(pluginMessage.nodeId)
figma.off('documentchange', onDocumentChange)
console.log('shit');
// update isWatching to false since we are no longer watching for changes
isWatching = false
}
}
}