Creating custom ExpandableListView, how to bind to "GroupTemplate" in axml - mvvmcross

I've created a bindable version of ExpandableListView based off of https://github.com/hlogmans/MvvmCross.DeapExtensions/ and put it in my app. I want to add a GroupTemplate that I can bind to in the axml which would be similar to MvxListView's ItemTemplate.
Do I need to subclass MvxAndroidBindingResource? I'm also confused as to how the MvxBindingAttributes fits in.

The easiest route for this might be for you to take a read through how MvxListView and MvxAdapter work.
The MvxBindingAttributes (https://github.com/MvvmCross/MvvmCross/blob/v3.1/nuspec/DroidContent/MvxBindingAttributes.xml) allow MvvmCross to add new xml tags to the axml files.
The MvxAndroidBindingResource class (https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Droid/ResourceHelpers/MvxAndroidBindingResource.cs) is the C# code to parse the values for the attribute tags defined in MvxBindingAttributes.
You can see this in action for an MvxListView in https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Droid/Views/MvxListView.cs#L33
public MvxListView(Context context, IAttributeSet attrs, IMvxAdapter adapter)
: base(context, attrs)
{
// Note: Any calling derived class passing a null adapter is responsible for setting
// it's own itemTemplateId
if (adapter == null)
return;
var itemTemplateId = MvxAttributeHelpers.ReadListItemTemplateId(context, attrs);
adapter.ItemTemplateId = itemTemplateId;
Adapter = adapter;
}
In particular, the line:
var itemTemplateId = MvxAttributeHelpers.ReadListItemTemplateId(context, attrs);
This uses the id values parsed in MvxAndroidBindingResource to read the axml tag value for local:MvxItemTemplate

Related

how data binding works between ng-template and the context passed to the template using CreateEmbeddedView

I have this template.
<ng-template #thumbnailTemplate let-context="thumbnailContext">
<div id="{{context.divId}}">
<img id="{{context.imgId}}" src="{{context.imgSrc}}">
</div>
</ng-template>
The following code create a view using the above template
thumbnailTemplateViewRef = this.thumbnailContainerRef.createEmbeddedView(this.thumbnailTemplateRef,
{thumbnailContext: new ThumbnailContext(divId,
imgId,
closeId,
imageString,this.thumbnailContainerRef.length,null)});
and when deleteThumbnail is called and the context is passed to it, I am accessing the index property as follows
let index = thumbnailContext.thumbnailContext.index;
deleteThumbnail(thumbnailContext:any){
console.log("delete thumbnail clicked with context ",JSON.stringify(thumbnailContext));
let index = thumbnailContext.thumbnailContext.index; //note that thumbnailContext.index is undefined
console.log("deleting index ", index);
let wasConfirmed = confirm("Are you sure you want to delete the attachment?");
if(wasConfirmed) {
this.thumbnailContainerRef.remove(index);
return false;
}
}
ThumbnailContext is
export class ThumbnailContext{
constructor(public divId:string,
public imgId: string,
public closeId:string,
public imgSrc:string,
public index:number,
public viewRefId:EmbeddedViewRef<ThumbnailContext>){}
}
I am unable to understand what the type of context is let-context=thumbnailContext is in the ng-template
Is context it
{
thumbnailContext:{divId:.., imgId:..}
}
or is context
{
divId:.., imgId:..,
}
In the html it looks like it is the latter one because I am able to assign the values in the html as div id="{{context.divId}}but when then I unable to do context.index in deleteThumbnail? Why I had to do thumbnailContext.thumbnailContext.index?
This is my understanding but it could be wrong so I am happy to accept other answers.
In templates, context information could be passed as an object and the passed object's key(s) will be available for binding by the local template let declarations.
eg, if the template is
<ng-template #myTemplate let-col let-foo="bar">
<div>{{col}}</div>
<div>{{foo}}</div>
</ng-template>
and if the object passed is myContext = {$implicit: 'World', bar: 'Svet'}; then col will be assigned the value World because it is assigned the $implicit key's value and foo is assigned value of bar key i.e. Svet
In my example if I use let-context="thumbnailContext" in the html then I need thumbnailContext key in the context object.
{thumbnailContext: new ThumbnailContext(divId, //storing information about this thumbnail in the context of teh embedded view
imgId,
closeId,
imageString,this.thumbnailContainerRef.length,null)}
then context becomes {divId:..., imgId:...} and I can use it as context.divId
alternatively I could have used let-context only along with $implicit
$implicit: new ThumbnailContext(...)
Now this is the part I am unsure of but the following is my understanding.Note that context variable in let-context is a key/value, not an object itself. In the example below
<ng-template #eng let-name><span>Hello {{name}}!</span></ng-template>, if the object passed is
myContext = {$implicit: 'World', localSk: 'Svet'};
then name is World (the value)
So when I pass context to deleteThumbnail, I am passing a key/value i.e. thumbnail:{divId:..., imgId:...). Javascript wraps this inside an object i.e.
{
thumbnailContext:{divId:..., imgId:...}
}
thus to access it inside deleteThumbnail, I'll have to do thumbnailContext.thumbnailContext.divId because the
top level object (function argument) is called thumbnailContext

Bidirectional binding for flex ComboBox?

I have a collection that I want to bind as data input for a ComboBox:
private static var LOGOS:ArrayCollection = new ArrayCollection([
{index:0, label=logo1},
{index:1, label=logo2}
]);
<s:ComboBox selectedItem="#{model.labelIndex}" labelField="#label" dataProvider="{LOGOS}" />
Now, when selecting an item, the binding should send the associated index property of the objext to the model and update labelIndex.
Of course it does not work as above, because labelIndex is of different datatype than the ArrayCollection.
[Bindable]
private var model:MyModel;
[Bindable]
class MyModel {
public var:Number labelIndex;
}
Question: how can I map the array element to the model and vice versa?
What you are looking for will require some scripting, binding isn't smart enough to figure out how to handle this on its own.
You can use the BindingUtils class to define the bindings, and use the chain argument of the bindProperty method to modify how values are being looked up.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/binding/utils/BindingUtils.html
For the combo.selectedItem to model.labelIndex binding, you can specify the chain as an array, where the elements define the path where to look for the value:
BindingUtils.bindProperty(model, 'labelIndex', combo, ['selectedItem', 'index']);
This will bind to the selectedItem property, and pass the value of the items index property.
The other way around is a little more tricky and will require using a getter function which grabs the object from the datasource, based on the labelIndex value:
BindingUtils.bindProperty(combo, 'selectedItem', model, {
name: 'labelIndex',
getter: function(host:MyModel):Object
{
return LOGOS.source.filter(function(item:Object, index:int, array:Array):Boolean
{
return item.index === host.labelIndex;
})[0];
}
});
This will bind to the labelIndex property, and the getter function will be invoked when the property changes. The function will filter the datasource based on the models changed labelIndex property value, and return the source object with the matching index property value, which will finally be set for the combobox selectedItem property.
Your combobox definition will of course need an id in order to be targetable via script
<s:ComboBox id="combo" dataProvider="{LOGOS}" />
Note that there's no need forthe the # in the labelField property, this is only used with XML datasources where you need to target an attribute. However, actually you don't need to specify this at all, since label is the default value of the labelField property.

Accessing HashMap action variables using JSONObject in JSP file

I am working with Struts2 with java action class and view JSP file.
My Action class has a variable named:
HashMap<Integer, Boolean> pcksHavingFet;
List<pck> pcks;
int fet;
In pcks, I am having a list of pck's with primary key pckId.
I am having a code function in action class that evaluates pcks and assign true/false based on if pck is/is not associated with fet in Database. So we get a fully evaluated expression for pcksHavingFet Map.
//Code that evaluates and set pcksHavingFet varaible.
//Create A JSON Object to access this Map variable in JSP.
public void function()
{
// code to populate pcksHavingFet with key/value pair.
//e.g, pcksHavingFet = {1:true, 2:fALSE, 6:TRUE, 17:false, 11:true .....}
//Create JSON Object to access Map in JSP file
JSONObject jasonfeat = new JSONObject();
jasonfeat.accumulateAll(pcksHavingFet );
}
In Jsp File,
I need to access this pcksHavingFet Map Variable.
I am using below function to show/hide fetDropdown drop down based on pckId is true/false calculated from Map pcksHavingFet.
function pcksOnChange(pckId)
{
var pcksHavingFet = <ww:property value="pcksHavingFet "/> ;
<ww:set name="pcksHavingFet" value="%{JSONObject.fromObject(pcksHavingFet)}">
</ww:set>
fetDropdown.style.display = (pcksHavingFet [pckId]) ? "" : "none";
}
But I am able to see populated values in my action class for pcksHavingFet variables. But In JSP file, unable to access it though. Its coming as empty Map.
Please help me in accessing successfully this variable. It will be a gr8 help. I am new to JSON, Please elaborate your suggestion/help.
Thanks in advance.
Why you are not using Struts2 Build in mechanism to handle JSON.Struts2 provide [Json-plugin].1
The JSON plugin is bundled with Struts since 2.1.7+
All you need to do is to add the plugin jar jar in your class path and need to extends json-default in place of struts-default and you are good to go.
Suggest you to read plugin page for details and example how to work with JSON inside Struts2
Strus2-Json
just as a side note ww represent web-work which has now merged in to Struts2 so its a bit more clear to use tag- alias as s in-place of ww, but the end choice is all yours.
When you are asking question about Struts2 better tag them with struts2 not struts :)

Refer to a Spark view component in code

I'm building a mobile AIR app using Flash Builder 4.5. The initial view in my views package is TestHomeView.mxml. I want to refer to it in one of my .as classes elsewhere in the app, and I'm not sure how to do that.
Theoretically I should be able to add an "id" attribute to TestHomeView.mxml, but FB gives me an error: "id is not allowed on the root tag of a component". The root tag is s:view.
The reason I need to do this is that within another class I make various calculations and then need to pass an array of values to a component in my view class. So in SomeOtherActionScriptClass.as I first assemble the array, myArray, and then in that class I want to do this:
myViewComponent.viewArray = myArray;
If I'm going to do that, I also need to import the view class into the .as class, which strikes me as weird. So is there a simple way to do what I want, or do I have to dispatch a custom event which contains the array, and listen for it in the view class?
EDIT - Based on the below MVC suggestion I did the following in model:
[Bindable]
public class Model
{
private static var myModel:Model;//doesn't let me name it 'model' because
//I have a package named 'model'
public var myArray:Array; //its value set later in model code
public function Model()
{
if ( Model.myModel != null ){
throw new Error( "Only one Model instance should be instantiated" );
}
}
// singleton: always returns the one existing static instance to itself
public static function getInstance() : Model {
if ( myModel == null ){
myModel = new Model();
}
return myModel;
}
Then in the view code I have:
[Bindable] //do I actually need this?
private var myModel:Model = Model.getInstance();
var viewArray = new Array();
viewArray = myModel.myArray;
But it is coming back null. It isn't null when I put a breakpoint in the Model class, but when I try to access it from the view class, it's null. The model itself isn't null, but that variable is.
What am I doing wrong?
Thanks.
First, if you are trying to make a singleton in AS3 you should first create a class, within the same class file as Model, that is used to ensure you can only create the class once.
Add this class at the bottom of the Model class file (outside of the Model class):
internal class SingletonEnforcer{}
Then create the Model constructor like this:
public function Model(enforcer:SingletonEnforcer){ Init(); } // if init code is needed
public static function get Instance():Model
{
if (!myModel){
myModel = new Model(new SingletonEnforcer());
}
return myModel;
}
Now you don't have to throw an exception for creating a second instance because it isn't possible.
I'm not sure about your first question of referencing your app's main mxml, but if you were asking how to call the app that is running (like WindowedApplication in AIR) then you would call it like this:
// my WindowedApplication file = MyApp.mxml
MyApp(this.parentApplication)
That will return the app's instance.
Once you've set up the Singleton like I have it above you should be able to access your array like:
Model.Instance.myArray;
I hope this helps!
Follow the MVC pattern.
Create Model class (make it Bindable) with a property viewArray. Bind to this property from your View. And in any other class just change viewArray property of the model. The binding event will be fired and this property will also be changed in your View. To make your Model "visible" from any point, you can make it a Singleton.

actionscript 3 MVC work flow

What's the best practice for passing data between the main class and the view class and vice versa?
main.as
var model : Model = new Model();
var view : View = new View();
var controller : controller = new Controller();
public function callFromView() : void {}
view.as
// how to reference the main.as
private function callToMain() : void
{
// please help
}
I generally handle communication by changing properties in the model via the controller. On change of values in the model, i will dispatch events representing those changes. Anyone (Main in this case) that has a reference to the model can subscribe to those events. This results in a more circuitous implementation, but to a very loosely coupled result.
Create a variable inside your View class called:
var main:Main;
Then a function to receive an object of type Main that sets the variable you created above, like this:
public function setMain(mainIN:Main):void
{
main = mainIN;
}
Now you have a local copy of all the data contained in your main document class in your View class. You can access properties of main by doing this (inside your view class' functions):
main.model.x = mouseX; //just an example. For this, your model variable inside Main would need to be public.
To do data passing the other way, you simply create public properties or functions inside your View class, and then because you've created the instance of View inside your Main class, it will be able to access it as normal with code like:
view.someViewFunction();
In this way each class has access to each other's properties and functions. I hope this helps!