Check if an item exists in dataprovider - apache-flex

Good afternoon.
I need to check if the item already exists before add in an dataprovider. But the indexOf method always return -1 wheen i try to do this check in my array. Anyone who can help me? Thank you.
var contacts:Array = new Array();
for each(var i:Object in windowAddContact.selectedContacts) {
if(contacts.indexOf(i) == -1) {
contacts.push(i);
}
}
contactList.dataProvider = contacts;

Given the code; you've provided; I wouldn't expect indexOf to return anything but -1; unless youhave multiple instances of the same object in windowAddContact.selectedContacts; which is possible but seems unlikely.
The contacts array starts out empty and all this code does is copy items from a collection into an Array. Try this:
var contacts:Array = new Array();
contacts.add(windowAddContact.selectedContacts[0]);
for each(var i:Object in windowAddContact.selectedContacts) {
if(contacts.indexOf(i) == -1) {
contacts.push(i);
}
}
And I'll bet you'll see indexOf(i) return something other than -1 once. I'm unclear what you're trying to do, though. Why is the loop necessary? Can't you just do:
contactList.dataProvider = windowAddContact.selectedContacts;

Related

ASP.net Sessions, references or not?..and how to write a session holding a list?

I have this property in my code:
public List<TreeViewNodeContentHolder> NodeContentHolder
{
get
{
if (Session["NodeContainerSession"] == null)
{
var tempSessionVar = new List<TreeViewNodeContentHolder>();
Session["NodeContainerSession"] = tempSessionVar;
return (List<TreeViewNodeContentHolder>)Session["NodeContainerSession"];
}
else
return (List<TreeViewNodeContentHolder>)Session["NodeContainerSession"];
}
}
and the thing I want to achive is that I want to be able to add objects and linq-query the list/session.
So basicly I whould like to be able to write something like:
NodeContentHolder.Add(new TreeViewNodeContentHolder{prop1=1,prop2=2});
I also want to be able to do this:
var someNode = NodeContentHolder.Where(e=>e.prop1 == x).FirstOrDefault();
And then another question aswell..if I whould do the thing above this line...whould I then be able to update the object in the session by doing:
someNode.prop1 = 12345;
??
Or whould I have to first "pull" the object and then remove it from the list/session and then add it back in to make sure that it gets updated?..
Thanks in advance!
All of that you say here is correct, all the list you mention here are save by reference, and if you keep on session the reference then the session is saved last, on page unload, so anything you change on the list is reflected on the object that session will be save.
The only think that I will change on your code is if Session["NodeContainerSession"] != null did not mean that is also a List<TreeViewNodeContentHolder>, this is a check that you must make.
public List<TreeViewNodeContentHolder> NodeContentHolder
{
get
{
object oSessionNode = Session["NodeContainerSession"] as List<TreeViewNodeContentHolder>;
if (oSessionNode == null)
{
oSessionNode = new List<TreeViewNodeContentHolder>();
Session["NodeContainerSession"] = oSessionNode;
}
return (List<TreeViewNodeContentHolder>)oSessionNode;
}
}

Sort collection and sort remains in place when adding to collection?

When I get a collection back from the service tier, I create an ArrayCollection and apply a sort. When I add an item to the collection later on, the sort is still in place? It seems to be the case. I thought I was only sorting it once, not applying a sort that will stick???
Here is the method for adding an item:
private function onAddNewClick():void
{
var fileTemplate:FileTemplateDetailDTO = new FileTemplateDetailDTO();
fileTemplate.fileTemplateId = 0;
fileTemplate.fileTmpltDtlId = 0;
fileTemplate.createdBy = appModel.userName;
newFieldsDp.addItem( fileTemplate );
this.fieldsGridEmpty.rowCount = newFieldsDp.length + 1;
totalCount = newFieldsDp.length;
this.fieldsGridEmpty.scrollToIndex( totalCount );
}
And here is what I'm trying now for when the data comes back from the service:
for each( var dto:FileTemplateCompositeDTO in coll ){
dto.templateHistory = createHistoryColl( dto.details );
var sortedArray:ArrayCollection = sortDetails( dto.details );
sortedArray.sort = null;
var freshArray:Array = sortedArray.toArray();
dto.details.source = freshArray;
model.fileTemplateComposites.addItem( FileTemplateCompositeDTO( dto ) );
}
Easiest way to do a one time sort:
var array:Array = yourArrayCollection.toArray():
array.sortOn("SomePropertyAvailableInEachItem", Array.DESCENDING | Array.NUMERIC);
yourArrayCollection.refresh();
Since you're not sorting the underlying Array, and not the collection.
No. You should call myCollection.refresh() every time it is changed. But you can listen for collectionChange event and call refresh from there:
private function collectionChangeHandler(event:CollectionEvent):void
{
if (event.kind == CollectionEventKind.ADD || event.kind == CollectionEventKind.REMOVE ||
event.kind == CollectionEventKind.REPLACE || event.kind == CollectionEventKind.MOVE || event.kind == CollectionEventKind.UPDATE)
{
ArrayCollection(event.currentTarget).refresh();
}
}
The sort of an ArrayCollection will remain linked to it. You can try to set the sort attribute to null after the initial sort and refresh, but I'm not 100% sure that a following refresh() will keep the elements order (although it should).
Another approach: after applying the initial sort to your collection, you can call its toArray() method to obtain a (sorted) array, then just create a new ArrayCollection passing that array as its source in the constructor. Note that ArrayCollection is really just a wrapper on array, so the toArray() and the construction of a new ArrayCollection for an existing array should not be heavy operations.
A Sort on an ArrayCollection is an object itself. When you assign the Sort object to the sort property on the ArrayCollection, it remains assigned until you remove it manually. To remove it, just set the sort property on your ArrayCollection to null after you call refresh().
myArrayCollection.sort = mySort;
myArrayCollection.refresh();
myArrayCollection.sort = null;
Now any time you call refresh() on the ArrayCollection, the sort is no longer in place.

Flex Advanced Data Grid w/ hierarchical data: How to access currentTarget fields on dragdrop event?

So this is driving me crazy. I've got an advanced data grid with a dataprovider that's an array collection w/ hierarchical data. Each object (including the children) has an id field. I'm trying to drag and drop data from within the ADG. When this happens, I need to grab the id off the drop target and change the dragged object's parentid field. Here's what I've got:
public function topAccountsGrid_dragDropHandler(event:DragEvent):void{
//In this function, you need to make the move, update the field in salesforce, and refresh the salesforce data...
if(checkActivateAccountManageMode.selected == true) {
var dragObj:Array = event.dragSource.dataForFormat("treeDataGridItems") as Array;
var newParentId:String = event.currentTarget['Id'];
dragObj[0].ParentId = newParentId;
} else {
return;
}
app.wrapper.save(dragObj[0],
new mx.rpc.Responder(
function():void {
refreshData();
},
function():void{_status = "apex error!";}
)
);
}
I can access the data I'm draggin (hence changing parentId) but not the currentTarget. I think the hierarchical data is part of the problem, but I can't find much in the documentation? Any thoughts?
event.currentTarget is not a node, it's the ADG itself. However, it's quite easy to get the information you want, since the ADG stores that data internally (as mx_internal).
I'm using the following code snippets (tested with Flex SDK 4.1) in a dragOver handler, but I guess it will work in a dragDrop handler too.
protected function myGrid_dragDropHandler(event:DragEvent):void
{
// Get the dragged items. This could either be an Array, a Vector or NULL.
var draggedItems:Object = getDraggedItems(event.dragSource);
if (!draggedItems)
return;
// That's our ADG where the event handler is registered.
var dropTarget:AdvancedDataGrid = AdvancedDataGrid(event.currentTarget);
// Get the internal information about the dropTarget from the ADG.
var dropData:Object = mx_internal::dropTarget._dropData;
// In case the dataProvider is hierarchical, get the internal hierarchicalData aka rootModel.
var hierarchicalData:IHierarchicalData = dropTarget.mx_internal::_rootModel;
var targetParent:Object = null;
// If it's a hierarchical data structure and the dropData could be retrieved
// then get the parent node to which the draggedItems are going to be added.
if (hierarchicalData && dropData)
targetParent = dropData.parent;
for each (var draggedItem:Object in draggedItems)
{
// do something with the draggedItem
}
}
protected function getDraggedItems(dragSource:DragSource):Object
{
if (dragSource.hasFormat("treeDataGridItems"))
return dragSource.dataForFormat("treeDataGridItems") as Array;
if (dragSource.hasFormat("items"))
return dragSource.dataForFormat("items") as Array;
if (dragSource.hasFormat("itemsByIndex"))
return dragSource.dataForFormat("itemsByIndex") as Vector.<Object>;
return null;
}
var dropData:Object = mx_internal::dropTarget._dropData;
should be
var dropData:Object = dropTarget.mx_internal::_dropData;
Try this.

Combine/merge Dynamic Objects in AS3

I have 2 dynamic objects and I want to build one to contain all the properties:
var o1:Object = {prop1:val1,prop2:val2,prop3:val3};
var o2:Object = {prop3:val3a,prop4:val4};
and I need to obtain a third object that looks like that:
{prop1:val1, prop2:val2, prop3:val3a, prop4:val4};
Basically I need a way to iterate through the object properties and to add new properties to the third object. I have to mention I'm quite new to AS3/Flash/Flex.
First question, do you really mean to have prop3 in both objects? you will need to decide what to do in case of a collision like that, which object has precedence.
Secondly, check out the introspection apis: http://livedocs.adobe.com/flex/3/html/help.html?content=usingas_8.html
something like this should work:
public function mergeDynamicObjects ( objectA:Object, objectB:Object ) : Object
{
var objectC:Object = new Object();
var p:String;
for (p in objectA) {
objectC[p] = objectA[p];
}
for (p in objectB) {
objectC[p] = objectB[p];
}
return objectC;
}
If the property exists in A and B, B's will overwrite A's. Also note that if the values of a property is an object, it will pass a reference, not a copy of the value. You might need to clone the object in those cases, depending on your needs.
Note: I haven't actually tested the above, but it should be close. Let me know if it doesn't work.
Updated to fix the errors. Glad it works for you though.
You can dynamically access/set properties on objects with the index operator. The for loop will itterate over the property names, so if you put it all together, the following test passes:
[Test]
public function merge_objects():void {
var o1:Object = {prop1:"one", prop2:"two", prop3:"three"};
var o2:Object = {prop3:"threeA", prop4:"four"};
var o3:Object = new Object();
for (var prop in o1) o3[prop] = o1[prop];
for (var prop in o2) o3[prop] = o2[prop];
assertThat(o3.prop1, equalTo("one"));
assertThat(o3.prop2, equalTo("two"));
assertThat(o3.prop3, equalTo("threeA"));
assertThat(o3.prop4, equalTo("four"));
}
you can iterate over the object properties like:
var obj1:Object = new Object();
for(var str:String in obj2){
obj1[str] = "any value"; // insert the property from obj2 to obj1
}

Flex 3: How do I determine if a generic Object is actually a button?

I have this bit of code, and it's not working as I expected. btnContainer is a VBox that contains a ton of buttons (toggle=true); and I want to reset them to un-toggled at a certain point.
for (var btn:Object in btnContainer.getChildren()){
if (btn.isPrototypeOf(mx.controls.Button)){
btn.selected = false;
}
}
With the above code, "btn" shows up as just the index during each iteration of the loop (0,1,2,3,...), and the conditional never evaluates to true.
I also tried this:
for (var btn:Button in btnContainer.getChildren()){
btn.selected = false;
}
This works fine, except that there is also a label inside btnContainer; so it throws an error when trying to cast the label as a button.
What am I doing wrong, here?
If you want to loop through the elements of an array, use a "for each..in" loop, and if you want to see if a variable is compatible with a given type (e.g. an instance of a given class), use the is operator.
The language reference has an example for this exact kind of case.
Here's the fixed code:
for each (var btn:Object in btnContainer.getChildren()){
if (btn is Button){
btn.selected = false;
}
}
Have you tried using is?
import mx.controls.Button;
//...
for (var key in btnContainer.getChildren()){
var obj : Object = btnContainer[key];
if (obj is Button){
var button : Button = obj as Button;
button.selected = false;
}
}

Resources