AS3 SharedObject IF isset or equals - actionscript-3

very new to SharedObjects, but essentially all I want to do is let a user answer a question once and not allow them to answer again, how is it possible. This is what I have below?
/*if(_question.data.seenQuestion == "true") {
cookie_txt.text = "COOKIE FOUND";
} else {
cookie_txt.text = "NO COOKIES";
}*/
var _question:SharedObject;
_question.data.seenQuestion = "true";
_question.flush();
_question.close();

You're very close. It looks like you're not actually creating a SharedObject, to do that you would use the method getLocal:
var _question:SharedObject = SharedObject.getLocal("questionData");
Additionally, since SharedObject supports primitive types (String, int, Number, Object, Boolean, etc), you should store a Boolean instead of a String:
if(_question.data.seenQuestion)
{
cookie_txt.text = "COOKIE FOUND";
}
else
{
cookie_txt.text = "NO COOKIES";
}
_question.data.seenQuestion = true;
_question.flush();
Lastly, if you're using a local shared object (more common), you don't need to call close().

You do need to create your SharedOBject or else your code will throw errors:
var _question:SharedObject = SharedOBject.getLocal("myapp");
No need for flush or close just assign/change some data and that's it.
_question.data.seenQuestion = "true";
However SharedObject is not a good solution for persistent data. User can erase it/reset it, etc ...

Related

Facing issues while updating the property value in polymer JS

I'm creating a very simple CRUD app using Polymer js but facing some issues while editing the records.
Here is the code for add/edit:
_addTodo() {
if(this.user.id) {
let foundIndex = this.users.findIndex( x => x.id === this.user.id);
this.users[foundIndex] = this.user;
this.set('users', this.users);
console.log(this.users);
}
else {
this.user.id = Math.floor((Math.random() * 100000) + 1);
this.push('users', this.user);
}
this.user = {};
}
Although I could see the values inside the users object getting changed in the browser console but it's not getting changed in the DOM/UI.
If I'm using a static user object like below then it works:
_addTodo() {
if(this.user.id) {
var users = [
{
id: 1,
name: 'xyz',
age: 21
},
{
id: 2,
name: 'xyz123',
age: 5
}
]
this.set('users', users);
console.log(this.users);
}
else {
this.user.id = Math.floor((Math.random() * 100000) + 1);
this.push('users', this.user);
}
this.user = {};
}
Even I have used "notifyPath" instead of "set" but that is also not working.
Could anyone please suggest what I am doing wrong here for which the user object is not getting changed in DOM?
Update:
As suggested below, I'm using splice for updating the array but still it's not working.
JSfiddle - https://jsfiddle.net/ansumanmishra/8490y4q8/1/
this.users[foundIndex] = this.user;
this.set('users', this.users);
Updating the DOM takes performance. Whenever set is used, Polymer dirty checks every value in the array, but you have already set the array to it's new value so when it compares (basically, it compares with itself), Polymer wont detect any updates and therefor wont update the DOM.
You can't however do this as solution: var newUserArr = this.users, and then modify newUserArr because objects and arrays only create references to each other.
var a = [1]
var b = a
b[0] = 2
console.log(a) // gives [2]
You will only end up with the same thing as above: Polymer dirty checking the array with itself. Remove the reference with JSON.stringify, and then set the new array. I use this method all the time.
if(this.user.id) {
let foundIndex = this.users.findIndex( x => x.id === this.user.id);
// Remove references
var newUserArr = JSON.parse(JSON.stringify(this.users)));
newUserArr[foundIndex] = this.user;
this.set('users', newUserArr);
}
EDIT
However, when you want to edit something, you also create a reference from the object in the array, so when you type in your inputs, you will update the object in the existing array users.
I fiddled with your fiddle, and now it works. What I did was that I added JSON.parse(JSON.stringify()) in the method _editUser() too.
http://jsfiddle.net/c6h2hwch/
From "Set a property or subproperty by path": "calling set on an object property won't cause Polymer to pick up changes to the object's subproperties, unless the object itself changes." Note example:
// DOES NOT WORK
this.profile.name = Alex;
this.set('profile', this.profile);
You need to replace this.profile with a new profile object, or update the path of each individual member of profile.
This isn't an observable change:
this.users[foundIndex] = this.user;
this.set('users', this.users);
You're modifying the array that this.users points to (in a way Polymer can't detect) and then setting this.users to the same array—this.set('users', this.users) is the same operation as this.users = this.users.
You have a couple options. One is to use this.splice:
this.splice('users', foundIndex, 1, this.user);
This says, "remove 1 item at foundIndex and insert this.user in its place.
The other option is to create a copy of the array (with Array.prototype.slice—note that's slice, not splice) to make the change observable:
const nextUsers = this.users.slice();
nextUsers[foundIndex] = this.user;
this.users = nextUsers;
I recommend this.splice because it doesn't make Polymer do quite as much work when re-rendering e.g. a dom-repeat for the array.

How to get the document using view in couchbase

I have a requirement wherein I have get the document from couchbase.
Following in the Map function that I am using for the same -
function (doc, meta) {
if (meta.type == "json" && doc!=null) {
emit(doc);
}
}
There is no reduce function. Also following is my java code to get the document -
List<URI> hosts = Arrays.asList(
new URI("http://<some DNS with port>/pools")
);
// Name of the Bucket to connect to
String bucket = "Test-Sessions";
// Password of the bucket (empty) string if none
String password = "";
//System.setProperty("viewmode", "development");
// Connect to the Cluster
CouchbaseClient client = new CouchbaseClient(hosts, bucket, password);
String designDoc = "sessions";
String viewName = "by_test";
View view = client.getView(designDoc, viewName);
Query query = new Query();
query.setIncludeDocs(true);
query.setKey(String.valueOf(122));
ViewResponse result = client.query(view, query);
Object object = null;
for(ViewRow row : result) {
if(null != row) {
object = row.getDocument();
}// deal with the document/data
}
System.out.println("Object" + object);
And the data that I have in couchbase is key - "122" and value - "true". But for some reason , I do not get any rows in the ViewResponse. What is going wrong can anyone help?
I don't understand what you are trying to achieve here, you are using a view to get a document by it's key? Key == 122? Why can't you just do client.get(122) ?
If you just need a list of all the keys in your bucket (of which you can use to pull back all documents via include docs) then make your function like so:
function (doc, meta) {
if (meta.type == "json") {
emit();
}
}
The key of the document is always emitted as an ID (viewRow.getId()). You don't need to emit the document, try to emit as little data as possible to keep view sizes small.
If you are needing to manipulate all the documents in your bucket be careful as the size grows, perhaps you'd need to look at pagination to cycle through the results. http://tugdualgrall.blogspot.com.es/
Also once you have the ViewResponse loop over it like so:
for(ViewRow row : result) {
row.getDocument(); // deal with the document/data
}
You don't need to be doing checks for null on the rows.

Can you override functions in AS3?

I am new to ActionScripting but I have done some Java. I was told they are kinda similar. I am coding my swf file with some AS3 integrated.
function init():void{
// do something
}
function init(var string:String):String{
// do something else
}
is this not allowed in AS? If not, is there another way of handling it besides?
Thanks in advance.
Yes, you can override functions. But the example you gave is not overriding - it's overloading. For overriding a function, you basically just create a function with the same signature and everything in a subclass and add the word "override" right before it.
You can't directly overload a function though. If you want a variable number of parameters, you have to use optional parameters instead. Like this:
function init(str:String = null):String
{
if (str == null)
{
// do one thing
return null;
}
else
{
// do another thing
return "someString";
}
}
And that's about the best you're going to be able to do in AS3. The inability to overload functions, at least strictly speaking, is a fairly common complaint and obvious shortcoming of the language.
Do you mean method overloading? Actionscript, sadly, does not support this.
To get around it, you can use default parameters, or just make your parameters a bit less constraining. This answer has some details on that.
You could try this:
function init(var string:String = "Default value"):String{
// do something
}
Actionscript does not support method overloading. However, based on the answer to this question you have other options.
If you just want to be able to accept any type, you can use * to
allow any type:
function someFunction( xx:*, yy:*, flag:Boolean = true )
{
if (xx is Number) {
...do stuff...
} else if (xx is String) {
...do stuff...
} else {
...do stuff...
}
}
If you have a large number of various parameters where order is
unimportant, use an options object:
function someFunction( options:Object )
{
if (options.foo) doFoo();
if (options.bar) doBar();
baz = options.baz || 15;
...etc...
}
If you have a variable number of parameters, you can use the ...
(rest) parameter:
function someFunction( ... args)
{
switch (args.length)
{
case 2:
arr = args[0];
someBool = args[1];
xx = arr[0];
yy = arr[1];
break;
case 3:
xx = args[0];
yy = args[1];
someBool = args[2];
break;
default:
throw ...whatever...
}
...do more stuff...
}
For cases where you need to call a common function to a number of
classes, you should specify the interface common to each class:
function foo( bar:IBazable, flag:Boolean )
{
...do stuff...
baz = bar.baz()
...do more stuff...
}

Entity Framework Code First - Orphaning solutions?

I have searched around for a good amount of time trying to find a satisfactory solution to the orphan issue common in EF.
One of the simplest forms of orphaning is the clearing of a collection of entities. The relationship between the entities is removed but the child entities still remain in the database.
My requirements: -
The clearing of the collection occurs in the domain and I want to simply be able to call clear and no more.
Any logic to figure out whether the relationship between the parent and child has been broken resulting in the delete needs to be encapsulated within the repository / DbContext.
I don't want to have to 'dirty' the domain with anything additional in order to solve this problem. This includes back references.
I suspect that this can't be solved as I have have spent considerable time looking for solutions but I ask out of hope!
Areas I have looked at are the ChangeTracker and any possible events which I can hook into, similar to AssociationChanged event which has popped up in various places. Something, somewhere in the DbContext must know that this relationship has been broken. How to access it, that is the question?
Thanks.
Can you try the following solution? Mb it fits your needs. The DeleteOrphans extension method must be called between DetectChanges and SaveChanges methods.
public static class DbContextExtensions
{
private static readonly ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>> s_navPropMappings = new ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>>();
public static void DeleteOrphans( this DbContext source )
{
var context = ((IObjectContextAdapter)source).ObjectContext;
foreach (var entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
{
var entityType = entry.EntitySet.ElementType as EntityType;
if (entityType == null)
continue;
var navPropMap = s_navPropMappings.GetOrAdd(entityType, CreateNavigationPropertyMap);
var props = entry.GetModifiedProperties().ToArray();
foreach (var prop in props)
{
NavigationProperty navProp;
if (!navPropMap.TryGetValue(prop, out navProp))
continue;
var related = entry.RelationshipManager.GetRelatedEnd(navProp.RelationshipType.FullName, navProp.ToEndMember.Name);
var enumerator = related.GetEnumerator();
if (enumerator.MoveNext() && enumerator.Current != null)
continue;
entry.Delete();
break;
}
}
}
private static ReadOnlyDictionary<string, NavigationProperty> CreateNavigationPropertyMap( EntityType type )
{
var result = type.NavigationProperties
.Where(v => v.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
.Where(v => v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One || (v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne && v.FromEndMember.GetEntityType() == v.ToEndMember.GetEntityType()))
.Select(v => new { NavigationProperty = v, DependentProperties = v.GetDependentProperties().Take(2).ToArray() })
.Where(v => v.DependentProperties.Length == 1)
.ToDictionary(v => v.DependentProperties[0].Name, v => v.NavigationProperty);
return new ReadOnlyDictionary<string, NavigationProperty>(result);
}
}

Why does TRY / CATCH overwrite default property values?

I'm using a Value Object which can receive an object when it is instantiated, so its default values can be updated directly when a new VO is created, like so:
public class SeatSettingsVO
{
public var globalPosition:Point = new Point(0, 0);
public var dealerChipOffset:Point = new Point(0, 0);
public var chipStackOffset:Point = new Point(0, 0);
public function SeatSettingsVO(obj:Object = null)
{
if (obj)
parseSettings(obj);
}
}
The parseSettings method uses a try/catch block in order to get only the existing properties in the object passed to the constructor (or at least, that would be the intention):
private function parseSettings(obj:Object):void
{
try
{
this.globalPosition = obj.globalPosition;
this.chipStackOffset = obj.chipStackOffset;
this.dealerChipOffset = obj.dealerChipOffset;
}
catch (error:Error)
{
}
}
Now consider this scenario: a new Value Object needs to be created, but with only one of the three properties defined:
new SeatSettingsVO({globalPosition:new Point(300, 277)})
The problem is that if obj does not contain a particular property (e.g. chipStackOffset), instead of maintaining the initial property value (Point(0,0)), the method overwrites it to null.
My guess is that accessing non-existent properties on an Object class instance, does not trigger an error, but rather, null is returned, which in turn causes the default value to be overwritten. Can anyone explain this behavior, and possibly suggest a solution ?
Thank you very much.
A slightly more succinct solution than the others:
this.globalPosition = obj.globalPosition || DEFAULT_GLOBAL_POSITION;
Like in Python, the || operator returns the first operand if that operand evaluates to something besides 0, null, false, NaN, "", or undefined. Otherwise, it returns the second operand as-is:
trace(new Point(3, 3) || "hi"); //(x=3, y=3)
trace(false || "hi"); //hi
trace("hi" || "bye"); //hi
trace(0 || null); //null
trace(NaN || 0); //0
trace("" || undefined); //undefined
trace(undefined || new Point(0.4, 0)); //(x=0.4, y=0)
trace(null || false); //false
As a result, you can use it to check whether a value is defined, use that value if so, and use a default value if not. I'm honestly not sure if it makes your code more or less readable, but it's an option.
Flex Objects have a hasOwnProperty() method that you might find useful. You can use this to check if a dynamic object has a parameter defined, and only pull it if it exists, instead of getting nulls.
if (obj.hasOwnProperty("globalPosition"))
this.globalPosition = obj.globalPosition;
//etc...
In this case, your object is dynamic so you don't get an exception if the property doesn't exist. You do, however, get undefined. undefined evaluates to null, so you can always say:
this.globalPosition = obj.globalPosition ? obj.globalPosition : default;
where default is whatever you want to put there... even this.globalPosition would work if you want to set it back to what it was.
You can also ask if the property exists:
if( "globalPosition" in obj)
private function parseSettings(obj:Object):void
{
try
{
this.globalPosition = obj.globalPosition;
this.chipStackOffset = obj.chipStackOffset;// when error occured here,
// this.chipStackOffset still waiting for a value to set and it sets to null.
// probably dealerChipOffset doesnt change by default value.
this.dealerChipOffset = obj.dealerChipOffset; // this is {0,0} point prob,didnt try it.
}
catch (error:Error)
{
}
}
I would use somthing like below. Hope it helps.
private function parseSettings(obj:Object):void
{
for(var name in obj){
this[name] = obj[name];
}
}