Deep Cloning in Actionscript - actionscript

What is the best method to deep clone objects in actionscript?

The best method to do this is by using the ByteArray with the method writeObject. Like this:
function clone(source:Object):* {
var copier:ByteArray = new ByteArray();
copier.writeObject(source);
copier.position = 0;
return(copier.readObject());
}
More information about this, here: http://www.kirupa.com/forum/showpost.php?p=1897368&postcount;=77

If you are trying to deep clone a display object, this is the only way it worked for me :
public static function clone(target:DisplayObject ):DisplayObject {
var bitmapClone:Bitmap = null;
var bitmapData:BitmapData = new BitmapData(target.width,target.height,true,0x00000000);
bitmapData.draw(target);
bitmapClone = new Bitmap(bitmapData);
bitmapClone.smoothing = true;
return bitmapClone;
}
Note that this will only copy visually the object.It will not copy methods or properties.
I used this when i loaded external images, and used them in multiple places.

Related

Does elementHandler in jspdf fromHTML support multiple elements?

I am using jspdf to convert an HTML page to PDF using fromHTML(). The HTML page includes multiple images, which I need fromHTML() to ignore in order to generate the PDF.
I want to use the elementHandler to ignore the images. However, I can only get that to work with a single element ID. Here is the way the documentation shows:
var elementHandler = {
'#ignorePDF': function (element, renderer) {
return true;
}
};
I have tried to replace the '#ignorePDF' ID reference to a reference with a class that applies to all of the images:
'.ignorePDF'
or to include multiple ID's (one for each image):
'#ignorPDF1,#ignorePDF2'
but neither of those approaches has worked for me. Is there another way to accomplish this?
i figured out both issues. To reference multiple items to ignore, set it up like this:
var elementHandler = {};
elementHandlers["#img1"] = function...
elementHandlers["#img2"] = function...
also best to create a function that you can reuse rather than defining it over and over.
As for the inability to use a variable for the key, that was a dumb javascript error on my part. The variable name can be used like this:
var img1 = "#img1";
elementHandlers[img1] = function...
The # character must be included.
It would be useful if the method were modified to permit a class value to be entered so that a single class could be used to denote all items to be ignored.
You can ignore all objects of the same class (called for example no-print), as follows:
var noprints = document.getElementsByClassName("no-print");
var elementHandler = {};
for (var i=0; i<noprints.length; i++) {
elementHandler['#'+noprints[i].getAttribute('id')] = function (element, renderer) { return true; }
};

working with Actionfilter

I have never worked with actionfilter so i dont really know how to use it, ive done som reseach but i dont completly understand it. But basicly im going to create a new controller, and i want my _Viewstart.cshtml to use this controller. The problem is that i dont know how to use this code to an actionfilter and then call this controller in _viewstart.
The code that i want in my controller is.
var TemplateIDSession = Session["TemplateID"];
if (TemplateIDSession != null)
{
int tempID = (int)TemplateIDSession;
var template = servicetemp.GetEntry(tempID);
var servicetemp = ServiceFactory.Instance.CreateTemplateService();
Response.ContentType = "text/css";
return RazorEngine.Razor.Parse(System.IO.File.ReadAllText(Server.MapPath("Content/Site.css")));
I think you should go about this in a different way, by using a HTML Helper for the CSS, like so:
public static class Helpers
{
public static string OrganizationStyleTemplate(this HtmlHelper html)
{
TagBuilder tagBuilder = new TagBuilder("style");
var templateIDSession = HttpContext.Current.Session["TemplateID"];
if (TemplateIDSession != null)
{
// retrieve your css from the database and insert it into the tag
tagBuilder.InnerHtml = dbObject.CSSYouveStored;
}
return tagBuilder.ToString(TagRenderMode.Normal);
}
}
Then usage would be like so:
#Html.OrganizationStyleTemplate()
P.S. If you need to analyze if the user is authenticated within that method, use:
HttpContext.Current.Request.IsAuthenticated

Breeze.js: how to transform a Breeze entity to a plain JSON object

I have an entity instance created using the metadata coming from the server:
breeze.NamingConvention.camelCase.setAsDefault();
...
var applicationType = metadataStore.getEntityType('Application');
var application = applicationType.createEntity();
None of the objects in this particular model has circular dependencies.
After the user has made some changes to the corresponding object, I need to perform some custom validation on that entity, so I need to convert that object back to its JSON simple form and send it back to a validation Controller (ASP.NET MVC4).
The question is how to transform the entity to JSON such that:
The resulting object reflects the naming conventions used in the server side.
The object contains simple properties and not knockout observables.
And does not contain any other additional property or function used internally by breeze.
I was expecting to find something like:
var json = application.toJS();
But such method does not exist. Using ko.toJS(application) also doesn't work because (1), (2) and (3) are not fulfilled.
I'm sure this should be trivially easy to do, but I just can't find anything even remotely related on the documentation.
UPDATE: You'll forgive me for the horrible hack, but because I'm in a hurry what I did that temporarily solved my problem was just exposing the unwrapEntities internal function of entityManager. I also changed the function definition a little bit (just to exclude that annoying entityAspect):
function unwrapEntities(entities, metadataStore, includeEntityAspect) {
var rawEntities = entities.map(function(e) {
var rawEntity = unwrapInstance(e);
if (includeEntityAspect !== undefined && includeEntityAspect === false) {
return rawEntity;
}
...
});
}
And because I have the entityManager available at all times in my services, I was able to extend my types definition to do something like the following:
function createApplicant(initialValues) {
var applicant = applicantType.createEntity(initialValues);
applicant.toJS = function () {
var unwrappedEntities = entityManager.unwrapEntities([applicant], entityManager.metadataStore, false);
return unwrappedEntities[0];
};
return applicant;
}
And that's precisely what I need:
var json = application.toJS();
This is a good idea! Could you please add it to the Breeze User Voice. It makes a lot of sense to expose the "unwrapping" of a Breeze entity.
Just a small side note, the unwrap "hack" that you wrote may not work in a future version of Breeze because we are currently in process of refactoring some of this code, but I will try to expose a "cleaner" version as part of the Breeze api.
This may be outdated solution but I did some hack in my typescript class to do this without help from the breeze core.
I did this hack since my breeze version and typing file did not include the unwrap method and I did not want to upgrade it just now.
Another benefit is that the result class is absolutely clean of any extra properties not included in the metadata as well as you can control if you want just the plain entity or if you want the related entities embedded in the result as well.
Just include this code in your typescript class to get this done:
public unwrapEntity(entity: breeze.Entity, includeRefs: boolean): any {
var refs = [];
return this.unwrapEntityInner(entity, refs, includeRefs);
}
private objInArray(obj: any, refs: Array<any>): boolean {
var ret = false;
for (var i = 0; i < refs.length; i++) {
if (obj === refs[i]) {
ret = true;
break;
}
}
if (!ret)
refs.push(obj);
return ret;
}
private unwrapEntityInner(entity: breeze.Entity, refs: Array<any>, includeRefs: boolean): any {
var data = {};
for (var prop in entity) {
if (entity.hasOwnProperty(prop) && ko.isObservable(entity[prop])) {
data[prop] = entity[prop]();
if (typeof data[prop] !== 'undefined' && data[prop] != null) {
if (typeof data[prop].entityAspect !== 'undefined') {
data[prop] = (includeRefs && !this.objInArray(data[prop], refs)) ? this.unwrapEntityInner(data[prop], refs, includeRefs ) : null;
}
else if ($.isArray(data[prop])) {
if (!includeRefs || this.objInArray(data[prop], refs))
data[prop] = [];
else {
var tmp = data[prop];
data[prop] = [];
for (var i = 0; i < tmp.length; i++) {
data[prop].push(this.unwrapEntityInner(tmp[i], refs, includeRefs));
}
}
}
}
}
}
return data;
}

Flash CS5 Handling "file does not exist" Error in a FileMode.READ situation

I'm working on a flash game in Flash CS5 Professional that will eventually be running on an iPhone (hence the iOS tag). I am currently designing the save game portion of the code and I'm trying to set up what happens when someone runs the game for the very first time and the save game file doesn't exist yet. Here is my code:
public class SaveGameFile extends MovieClip {
private var file:File;
private var savedGame:XML;
public function SaveGameFile() {
addEventListener(Event.ADDED_TO_STAGE, addedFileSystem);
}
private function addedFileSystem(event:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, addedFileSystem);
file = File.applicationStorageDirectory;
file = file.resolvePath("saveGame1.xml");
xmlLoad();
}
private function xmlLoad():void {
var fileStream:FileStream = new FileStream();
fileStream.addEventListener(IOErrorEvent.IO_ERROR, ioReadErrorHandler);
fileStream.open(file, FileMode.READ);
fileStream.addEventListener(Event.COMPLETE, xmlLoadCompleteHandler);
}
private function xmlLoadCompleteHandler(event:Event):void {
var fileStream:FileStream = event.target as FileStream;
fileStream.removeEventListener(Event.COMPLETE, xmlLoadCompleteHandler);
var str:String = fileStream.readMultiByte(file.size, File.systemCharset);
savedGame = XML(str);
fileStream.close();
}
private function ioReadErrorHandler(event:Event):void {
var fileStream:FileStream = event.target as FileStream;
fileStream.removeEventListener(IOErrorEvent.IO_ERROR, ioReadErrorHandler);
createFile();
xmlSave();
}
In the ioReadErrorHandler I have two more functions that basically create the XML file and put it into the savedGame variable. Then xmlSave creates the XML file. At least this is what is supposed to happen. Right now when it gets to
fileStream.open(file, FileMode.READ);
I get the Error #3003: File or directory does not exist, which means my ioReadErrorHandler isn't doing the trick here. If I create the file and save it, then this code works perfectly and I can trace(savedGame) and it shows up just fine. But if I try to get it to create it (which as I mentioned it must when the game is first run) this is where I end up. Am I missing something here or is the IOErrorEvent.IO_ERROR not what I need to make this work?
Also once this is done (and working properly of course), will it go back to FileMode.READ and try again? Or does the error essentially break you out of the function and it needs to be run again?
As mentioned in the comment to my own post, I found the correct way to handle this synchronous operation. Here is the corrected code if anyone searching this wants to know:
public class SaveGameFile extends MovieClip {
private var file:File;
private var savedGame:XML;
public function SaveGameFile() {
addEventListener(Event.ADDED_TO_STAGE, addedFileSystem);
}
private function addedFileSystem(event:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, addedFileSystem);
file = File.applicationStorageDirectory;
file = file.resolvePath("saveGame1.xml");
xmlLoad();
}
private function xmlLoad():void {
var fileStream:FileStream = new FileStream();
try {
fileStream.open(file, FileMode.READ);
} catch(e:IOError) {
createFile();
xmlSave();
}
var str:String = fileStream.readMultiByte(file.size, File.systemCharset);
savedGame = XML(str);
fileStream.close();
}
Again "createFile():" runs a function that creates the XML file and saves it to the variable "savedGame". Then "xmlSave();" runs a function to actually save the file so xmlLoad has something to load when this is run the very first time on a new device.

what's the best practice to attach a entity object which is detached from anthoer ObjectContext?

As mentioned in the title, how many methods are available?
I just have this case: I get a entity object from one ObjectContext, and then I detach the entity obejct from OjbectContext object, and return it.
Later, if I make some changes on this object, and I want to save the changes back to database. I think I should write like this, right? (Well, this works for me.)
public Url GetOneUrl()
{
Url u;
using(ServicesEntities ctx = new ServicesEntities())
{
u = (from t in ctx.Urls select t).FirstOrDefault<Url>();
ctx.Detach(u);
}
return u;
}
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
var t = ctx.GetObjectByKey(_Url.EntityKey) as Url;
ctx.Detach(t);
ctx.Attach(url);
ctx.ObjectStateManager.ChangeObjectState(url, System.Data.EntityState.Modified);
ctx.SaveChanges();
}
}
Url url = GetOneUrl();
url.UrsString = "http://google.com"; //I just change the content.
SaveToDB(url);
OR
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
var t = ctx.GetObjectByKey(_Url.EntityKey) as Url;
t = url; //this will make t.UrlString becomes "http://google.com"
ctx.ApplyCurrentValues<Url>("Urls", t);
ctx.SaveChanges();
}
}
This way is also works for me.
The first way will generate sql statement to update all the columns of Url table, but the second method will provide a sql script only update the "UrlString" Columns.
Both of them will have to retrieve a temp entity object from database which is the 't' in above code.
Are there any other methods to achieve this purpose? Or other better method you know about it? Or any official solution about this topic?
Many Thanks.
I don't understand your first example. Why do you first get entity from ObjectContext? It is not needed because you have just created new instance of the context. You can just use:
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
ctx.Attach(url);
ctx.ObjectStateManager.ChangeObjectState(url, System.Data.EntityState.Modified);
ctx.SaveChanges();
}
}
In your second example you can just call:
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
var t = ctx.GetObjectByKey(_Url.EntityKey) as Url; // Ensures that old values are loaded
ctx.ApplyCurrentValues<Url>("Urls", url);
ctx.SaveChanges();
}
}
Now the difference between two approaches is clear. First approach (Attach) does not need to query the DB first. Second approach (ApplyCurrentValues) needs to query the DB first to get old values.
You can use two additional approaches. First is just extension of your former approach. It allows you defining which properties were changed. Second approach is manual synchronization with loaded entity. This approach doesn't use any special methods. You will simply set loaded entity's properties to required values manually. This approach is useful if you work with object graph instead of single entity because EF is not able to automatically synchronize changes in relations.

Resources