This is a read-only archive of the Framer Community on Facebook.

What is Framer? Join the Community
Return to index
Dave Marchuk
Posted Feb 18 - Read on Facebook

I'm trying to duplicate an element and cloneNode() and clone() aren't working (view doesn't have the method). I couldn't find anything in the framerjs docs mentioning cloning. Thanks!

12 Comments

Dave Marchuk

I was doing some playing around and tried to re-use an object in the psd (I created it in both app.js and views.[filename].js as it's own object), but that created a js error saying the object didn't exist. Is there a way to create multiples of a single object from a single folder in the PSD or is that not going to work? I'm trying to save the designer some time replicating the same object 10 times repeatedly)

Koen Bok

There is no clone or copy in Framer yet. But I think this might work:

function copyView(view) {
var viewB = new View();
viewB.properties = view.properties;
return viewB;
}

Dave Marchuk

Hi Koen, how would I access viewB? I can get it to show itself within the function, but I'm getting not defined errors outside of the function.

Here's what I'm trying to do fully:

In the PSD, I have a "draggable" folder, which is a single layer icon. I need to create 10 of these icons that I can access separately as they have to get dragged around independently (like a game of checkers).

Do you think this is possible to do programmatically with FramerJS as is? My other option is to get the designer to leg-work the duplication within the PSD.

Koen Bok

Say if you need 20 view copies in an array you would do:

var newViews = [];

for (var i=0; i<20; i++) {
newViews.push(copyView(PSD.modelView));
}

Dave Marchuk

Hi Koen, sorry to ask but can you explain what the newView = copyView(modelView); is actually doing? I understand the looping through

Koen Bok

Yes. So the return keyword in the function passes back the newly created copy of the view you pass in. So newView is assigned with it's copy in this example.

Ninh Bui

Koen there are some caveats that I'd like to point out with your #copyView snippet for the uninitiated in that it's performing a shallow copy of View at best. In particular, the snippet is creating a new View and directly *assigning* its property reference to the original property reference (rather than copying the property object). This means that when the original or "copied" view's properties _state_ gets changed, all referring instances will notice side effects of this.

More often than not, this is not what you want when working with copies as you expect them to be independent copies. In this instance however, they would not be: even though the View objects themselves are allocated separately, they all reference the same properties hash. This means that after the proposed copy method, if I do view.properties["opacity"] = 0.5 , you should see all "copies" turn half opaque/transparent ;-) (apologies if this is not the exact format, I just quickly glanced at Framer's source).

If this is not the behaviour you want, and you'd need the instances to be independent as much as possible, then you'll need to implement a deep copy strategy.

Dave Marchuk

Yeah that's what I found... My copies acted like the same object when events were triggered

Ninh Bui

Dave yeah, that's expected behavior ;-) Normally, you'd need to implement a deep copy method that recursively drills down on the objects properties until it reaches the primitive values that comprise it. And then reconstruct the appropriate objects going from there :) You might want to ask Koen to implement this on a base object of Framer instead (e.g. Frame).

In the mean time, instead of going through those loops, it might also be good to just look at what "properties" actually stores; from the outset, it looks like a simple JSON object that doesn't reference complex types. In a case like this, I reckon you can use a clever hack by first serializing the object to a string, and then unserializing it again: the serialization to string will create a _new_ string containing the object structure and state. The unserialization basically re-assembles a _new_ object then based on the string data it was fed. The emphasis here is on _new_, as they should be separate copies then.

So try this instead:
function copyView(view) {
var newView = new View();
newView.properties = JSON.parse(JSON.stringify(view.properties));
return newView;
}

Haven't tested this, but let me know if it works :)

Dave Marchuk

I'll give it a go on Monday! Thanks Ninh!

Ninh Bui

Dave np, alternatively, you might also want to look at https://github.com/koenbok/Framer/blob/master/src/utils.coffee#L281 ; after digging around a bit more, I found this copy method provided in Framer's utils. I assume it leverages underscore.js's extend method to copy an object's properties ( http://underscorejs.org/#extend ), but does so in a shallow manner according to: http://techiella.wordpress.com/2013/04/02/underscore-js-extend-vs-jquery-extend/. If "properties" does not have nested objects, that should suffice. If it does however have nested objects, you'll need a deep copy.

Koen: would perhaps be a good idea to introduce a deepCopy utils method? Something like: http://coffeescriptcookbook.com/chapters/classes_and_objects/cloning ? Code looks pretty much like the recursive copy strategy I proposed a few posts back; you'll just need to check if the licenses are compatible I guess ;)

Dave Marchuk

Yeah, we had to just replicate layers due to timing... I'll try this if I get a chance to do some refactoring... otherwise, I'll use it on my next project for sure. Thanks for all the investigation Ninh!

Read the entire post on Facebook