Titanium Alloy Binding Model Collection with Array Inside Model - binding

Hi all I have an Alloy model like this
{
name: xxx,
lastName: yyy,
telephoneNumber: ["333","444","55"]
}
I want to bind a collection of this model to a table view but I don't know how to bind telephoneNumber's array.
I want to have a label for each number into telephoneNumber like this.
<Collection src="people"/>
<TableView dataCollection="people">
<TableViewRow>
<View layout="vertical">
<Label text="{name}"></Label>
<View ng-repeat="number in people.telephoneNumber">
<Label text="{number}"></Label>
</View>
</View>
</TableViewRow>
</TableView>
My question is, does exists something like angular ng-repeat for titanium alloy?
Thanks for answer

Your best bet is dataTransform function.
<TableView dataCollection="people" dataTransform="transformModel">
Then in your controller:
function transformModel(model){
var data = model.toJSON();
data.firstNumber = data.telephoneNumber[0];
return data;
}
Then you can use the property firstNumber in your alloy view and display it properly.
You can read more about dataTransform at the docs

Related

SAPUI5 Variant Management Save Button

expert.
I use the API 「sap.ui.comp.varinats」 to implement variant management.Save the variant data to S/4 via OData.
The "SAVE" button is invisible, so I want to enable it.
I referred to the article below, but it didn't work.
https://answers.sap.com/questions/12086627/variant-management---save-option.html
I want to enable this "SAVE" button when the view has finished loading, but I have a problem.
I want to get the oVariantSave function using this.getView().ById("vm").
I can get the oVariantSave function in onSelect. But I can't get the oVariantSave function in onAfterRendering.
enter image description here
enter image description here
<View>
<mvc:View xmlns:mvc="sap.ui.core.mvc"
xmlns:v="sap.ui.comp.variants"
controllerName="Test.controller.View1" displayBlock="true">
<App id="app">
<Page id="page" title="{i18n>title}">
<content>
<v:VariantManagement id="vm" select="onSelect" save="onSave" enabled="true" manage="onManage" showExecuteOnSelection="false"
showShare="false" showSetAsDefault="false" variantItems="{Variants>results}">
<v:variantItems>
<v:VariantItem text="{Variants>Varname}" key="{Variants>Varkey}" author="{Variants>Userid}"/>
</v:variantItems>
</v:VariantManagement>
<Controller>
//i can't get oVariantSave function
onAfterRendering: function () {
var oVariantMgmtControl = this.getView().byId("vm");
}
//i can get oVariantSave function
onSelect: function (oEvent) {
var oVariantMgmtControl = this.getView().byId("vm");
}
Please tell me how to get the oVariantSave function in onAfterRendering and enable the "SAVE" button before the user takes action.
Thanks and Regards
If you want to enable SAVE button, you must set currentVariantSetModified to true.
For example:
this.byId("variantManagment").currentVariantSetModified(true);
I hope that I am helpful :)

How to properly use TabNavigator inside another React Component

Question - How to properly use React Navigation's TabNavigator container component inside another React component that acts just as wrapper component?
What I want to achieve - Basically I want the appbar and tabbar both to be displayed - appbar on the top, tabbar (TabBarTop) just beneath it, a very common design pattern.
I have tried a couple of ways.
Method #1 (Nesting inside StackNavigator)
Tab.js
export const Tab = TabNavigator({
Tab1: { screen: Tab1Container },
Tab2: { screen: Tab2Container }
}, {
tabBarComponent: TapBarTop,
tabBarPosition: 'top'
});
AppBar.js
class AppBarComponent extends Component {
static navigationOptions = { header: null }
render() {
return (
<View>
*some more views, buttons blah blah here
</View>
)
}
}
export default AppBarComponent;
and I use them inside StackNavigator, like
export default StackNavigator({
stack1: { screen: AppBarComponent },
stack2: { screen: Tab }
});
This results in only 1 stack to be displayed at a given time which is exactly how it works. And I don't have anything to do with initialRouteName.
Method #2 (wrapping inside another component)
<View style={{ flex: 1 }}>
<AppBarComponent />
<Tab />
</View>
This on the contrary displays both components but this.props.navigation.navigate('somepath') or push() or pop() or
replace() doesn't work from inside and . But this.props.navigation and its methods all are available inside those components.
PS - I'm using React Navigation v1 and running on iOS
Solution for Method 1
Have a StackNavigator with only one screen and show your TabNavigator in that screen. Then customize header with your custom AppBarComponent.
header
React Element or a function that given HeaderProps returns a React
Element, to display as a header. Setting to null hides header.
Sample
export default StackNavigator({
stack: {
screen: Tab,
navigationOptions: {
header: (HeaderProps) => (<AppBarComponent headerProps={HeaderProps} />)
}
}
});
Solution for Method 2
You can wrap your component which is not a part of the stack with withNavigation HOC.
withNavigation is a higher order component which passes the
navigation prop into a wrapped Component. It's useful when you cannot
pass the navigation prop into the component directly, or don't want to
pass it in case of a deeply nested child.
Sample
class AppBarComponent extends Component {
static navigationOptions = { header: null }
render() {
return (
<View>
*some more views, buttons blah blah here
</View>
)
}
}
export default withNavigation(AppBarComponent);
#bennygenel your answer is definitely useful in addressing the problem. I kind of fed wrong information when I talk about having components inside TabNavigator. Well, instead of dumb components, there were multiple redux containers inside the TabNavigator as screens and the entire TabNavigator wrapped in a Dumb component. I have edited my question sincerely.
Though this.props.navigation exists both inside the redux containers and the wrapper component, the navigation stack reference was different for them which is why methods such as navigate or goBack() were not working.
The solution was simple. Passing the navigation stack reference as screenProps to the wrapper component solves this issue.
<View style={{ flex: 1 }}>
<AppBarComponent />
<Tab screenProps={{ rootNav: this.props.navigation }} />
</View>

New GMSMapView not working, but old GMSMapView loading properly

When I create a new GMSMapView it does not load. I have other GMSMapViews in my project that do load properly. I am using the storyboard editor to assign the custom subclass of GMSMapView to a UIView. Why are the new ones not working?
I found the solution to this issue by looking at the source code for my storyboard file.
My old GMSMapViews looked like this:
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO"
id="hbm-BT-3Ow" customClass="GMSMapView">
My new ones looked like this:
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO"
id="alb-9Z-Vu8" customClass="GMSMapView"
customModule="{My Project Name}" customModuleProvider="target">
When I set the custom class to GMSMapView for a new UIView, the associated Module was 'my project' instead of 'none' as it was previously.
The issue was that I created a custom extension for GMSMapView in my project.
extension GMSMapView {
var visibleBounds: GMSCoordinateBounds {
return GMSCoordinateBounds(region: self.projection.visibleRegion())
}
}
Solution:
Changing extension GMSMapView to extension GoogleMaps.GMSMapView fixed my problem.

Create dynamic number of rows from xml appcelerator ios

I have created xml file like below :
//cityState.xml
<Alloy>
<Window id="cityStateMgWin">
<TableView id="cityAndStatesTableView" >
<TableViewRow id="cityStatesRow" ></TableViewRow>
</TableView>
</Window>
//In cityState.js
I am trying to create state rows dynamically with the following code.
for (var i = 0; i < cityAndStatesListJSONData.length; i++) {
$.cityAndStatesTableView.appendRow(Alloy.createController('cityStatesRow', {title : cityAndStatesListJSONData[cityStates].cityState}).getView());
}
When i run the following error will coming please help me
message = "Object is not a constructor (evaluating 'new (require(\"alloy/controllers/\" + name))(args)')";
[ERROR] : stack = "createController\nonload";
is there any mistake to get the ui element from xml file to controller and create dynamic number of rows.
Thanks in advance.
A couple suggestions.
You have underscore available in Alloy
You cannot create a controller based on ID, it needs to be an actual controller.
So... looping through your data is easier this way:
_.each(cityAndStatesListJSONData, function(cityAndState){
});
Next, make a controller cityStatesRow for your row. Should look like this
JS File of this controller:
if ($.args.data.labelProp){
$.myLabel.text = $.args.title;
}
You can do this with as many items as you like, images, labels etc. Whatever you want in the row.
Within the _.each loop you will want to create the controller and pass the data to it:
var controller = Alloy.createController('cityStatesRow', {title : cityAndState.cityState});
And now append it to your TableView
$.cityAndStatesTableView.appendRow(controller.getView());

ImageView in ListView briefly shows previous image on scroll with RecycleElement enabled

I have a list of the following class:
public class Set {
public string IconUrl { get; set; }
}
This list is bound to a ListView:
<ListView ItemsSource="{Binding Sets}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Image Source="{Binding IconUrl}" />
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When the view loads and the user starts scrolling, the cells are reused and the Image briefly shows the previous image before the new image is downloaded and rendered.
Is there a way to prevent this kind of behavior without disabling RecycleElement?
I haven't tried this but on ViewCell you have Disappearing and Appearing events that you can hook into.
You may want to look at releasing the image source on the Disappearing event handler, but sometimes this can occur sometime later I think from recollection, so you may also want to try releasing the image on the Appearing event handler that hopefully will be executed prior to the display on the screen?
We have solved this by manually setting the Image source to null to force the render of the new images. we achieve this by using OnBindingContextChanged Event of the ListView. Hope this helps.
Edited (Added code below):
We have something like this:
public class PeopleCell : ViewCell
{...
Image profileImage;
public PeopleCell()
{
profileImage = new Image
{
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
BackgroundColor = Color.FromHex("f5f5f5"),
Source = ImageSource.FromFile("profile_blankimage"),
};...
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
people = BindingContext as CustomerViewModel;
if(people.Customer.Avatar != null)
profileImage.Source = ImageSource.FromUri(new Uri(people.Customer.Avatar.Url));

Resources