I do not know if I am doing it right or using any good practices, but I am trying to require and add views on my view.
but here I have a view container in my index.xml
<View id="containerDays" layout="vertical" height="Titanium.UI.SIZE">
<Require id="requiredDay" src="NewDay"/>
</View>
<Label id="buttonAddDay" class="button" >Adicionar outro dia</Label>
also on the index.js I have:
$.buttonAddDay.addEventListener("click", addNewDay);
function addNewDay () {
var novoDia = $.getView("NewDay");
$.containerDays.add(novoDia);
}
also I have the view here in another folder on:
/app/views/NewDay.xml
and inside that view is a simple input
<Alloy>
<View class="containerNewDay" layout="vertical" height="Titanium.UI.SIZE">
<TextField id="Day" >write a new day</TextField>
</View>
</Alloy>
so summing everything up,
I am trying to add my $.containerNewDay inside my $.containerDay, but I am not having any success with the getView() or the .open()
I will have to use all the textfield items to send it to a server, how can I set the ids but unfortunately I have no Idea how to do that on appcelerator.
Re the answer above, are you including the .add method from your original block of code? so it should be:
$.buttonAddDay.addEventListener("click", addNewDay);
function addNewDay () {
var novoDia = Alloy.createController("NewDay").getView();
$.containerDays.add(novoDia);
}
or better, would be:
function addNewDay () {
$.containerDays.add(Alloy.createController("NewDay").getView());
}
as this doesn't leave a pointer open to the view.
if you wanted to make it even cleaner:
$.buttonAddDay.addEventListener("click", function addNewDay () {
$.containerDays.add(Alloy.createController("NewDay").getView());
});
or if you want to stick to a "pure" Alloy way, then leave the addNewDay function in place and just add an onClick="addNewDay" handler in the button XML.
Crucially, remember that you'll need your containing view ContainerDays to have a layout of horizontal or your added views will simply sit on-top of each other.
Change:
$.buttonAddDay.addEventListener("click", addNewDay);
function addNewDay () {
var novoDia = $.getView("NewDay");
}
To:
$.buttonAddDay.addEventListener("click", addNewDay);
function addNewDay () {
var novoDia = Alloy.createController("NewDay").getView();
}
Related
I'm trying to implement an action bar with a search-bar in it along with one buttton to show/hide the search-bar.
At start the search-bar must be hidden. Only must be showed title of action-bar and a action item to show search-bar. In the view is working as expected, but the problem arises when I go to another view and then go back to this view. The search-bar is not hidden, but neither is the button. I'm using an observable with a boolean to control the items.
When is tapped onSearch search-bar shows up, and when I catch the clear event I set search-bar to be hidden.
Finally, I am also facing that when I go back to this view, the clearEvent event is called two or three times. I don't understand why this behaviour. I have tried in Android so far.
When I launch the app, the action bar looks like the first image.
If I tap on the search icon the action bar is like the second one
And when I go to a different view and go back is like the third one:
Edit, I have changed the code needed but it does not work yet. Here it's a complete view and js file to reproduce the problem:
xml:
<dpg:DrawerPage navigatedTo="onNavigatedTo" navigatingTo="navigatingTo"
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:dpg="nativescript-telerik-ui/sidedrawer/drawerpage"
xmlns:drawer="nativescript-telerik-ui/sidedrawer"
xmlns:component="customcomponents/menu"
xmlns:lv="nativescript-telerik-ui/listview"
loaded="loaded"
>
<ActionBar class="actionB" title="stores" >
<android>
<NavigationButton icon="res://ic_menu_black_24dp" tap="showSlideout" />
</android>
<ios>
<ActionItem icon="res://ic_menu" ios.position="left" tap="showSlideout" />
</ios>
<ActionItem>
<ActionItem.actionView>
<SearchBar id="search" class="blank" backgroundColor="#3C5AFD" hint="Search..." visibility="{{ myShowSearchBar ? 'visible' : 'collapsed' }}" />
</ActionItem.actionView>
</ActionItem>
<ActionItem tap="onSearch"
ios.systemIcon="12" ios.position="right"
android.systemIcon="ic_menu_search" android.position="actionBar" visibility="{{ myShowSearchBar ? 'collapsed' : 'visible' }}"/>
</ActionBar>
<dpg:DrawerPage.sideDrawer>
<drawer:RadSideDrawer id="drawer" drawerSize="270">
<drawer:RadSideDrawer.drawerContent>
<component:menu />
</drawer:RadSideDrawer.drawerContent>
</drawer:RadSideDrawer>
</dpg:DrawerPage.sideDrawer>
</dpg:DrawerPage>
the js file:
var frameModule = require("ui/frame");
var observable = require("data/observable");
var searchBarModule = require("ui/search-bar");
var topmost;
var drawer;
var page;
var observableView = new observable.Observable({myShowSearchBar: false});
exports.loaded = function(args) {
page = args.object;
topmost = frameModule.topmost();
observableView.set("myShowSearchBar", false);
page.bindingContext = observableView;
drawer = page.getViewById("drawer");
var searchBarView = page.getViewById('search');
if (searchBarView.android) {
searchBarView.android.clearFocus();
}
searchBarView.on(searchBarModule.SearchBar.submitEvent, function (args) {
console.log("Search for " + (args.object).text);
observableView.set("myShowSearchBar", false);
});
searchBarView.on(searchBarModule.SearchBar.clearEvent, function (args) {
observableView.set("myShowSearchBar", false);
});
};
exports.showSlideout = function(){
drawer.toggleDrawerState();
}
exports.onSearch = function(args){
console.log("onSearch");
observableView.set("myShowSearchBar", true);
}
args.object is not the page when accessing it in the clearEvent or via onSearch method. And just before that you are creating the observable property myShowSearchBar for the page.bindingContext. So basically, you are handling different binding contexts.
Better (for readability and reuse) to create the separated view-model and access it via a known variable.
e.g.
var myViewModel = new Observable();
exports.loaded = function(args) {
myViewModel.set("myShowSearchBar", false);
page.bindingContext = myViewModel;
}
exports.onSearch = function(args){
myViewModel.set("myShowSearchBar", true);
}
Even better if use separation of concerns and extract the whole view-model in an own file and then import it.
I am working on a react native app where I am trying to make some images act like a button so that when you press on them they print a statement in the console.
The images are displayed like this:
The code I have is:
class ImageList extends Component {
componentWillMount(){
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.dataSource = ds.cloneWithRows(this.props.images);
}
imageTouched(){
console.log('pressed');
}
renderRow(rowData){
const {uri} = rowData;
return(
<View style={{padding: 1, alignSelf: 'flex-start'}}>
<TouchableHighlight onPress={this.imageTouched}>
<Image style={styles.imageSize} source={{uri: uri}} />
</TouchableHighlight>
</View>
)
}
render() {
return (
<View>
<ListView
contentContainerStyle={styles.list}
dataSource={this.dataSource}
renderRow={this.renderRow}
/>
</View>
);
}
}
var styles = StyleSheet.create({
imageSize: {
//newWidth is the width of the device divided by 4.
//This is so that four images will display in each row.
width: newWidth,
height: newWidth,
padding: 2
},
list: {
flexDirection: 'row',
flexWrap: 'wrap'
}
});
When I run it there are no errors but when I touch the images nothing happens. I have checked the console but nothing is printed.
How do I get each image to act as a button?
Like others have mentioned, the problem is that this is not bound in the renderRow()-method. I think the easiest way to fix this is to change renderRow() to be an arrow-function:
renderRow = (rowData) => {
const {uri} = rowData;
return (
<View style={{padding: 1, alignSelf: 'flex-start'}}>
<TouchableHighlight onPress={this.imageTouched}>
<Image style={styles.imageSize} source={{uri: uri}} />
</TouchableHighlight>
</View>
);
}
Arrow function always have this set to their containing scope when invoked, so now this.imageTouched will resolve.
Notice that you don't have to do anything with your imageTouched()-function or invocation, since it's not referencing this.
PS. This syntax depends on Public Class Fields, which is a Stage 2 proposal of the language standard at the time of writing (likely to be included, already in use in internal React-code). This feature is possible to use with a babel-plugin that is enabled by default in React Native projects.
PS2. Note that declaring the method with an arrow function instead of using an arrow function in the invocation will create one instance of the method per component instance, instead of one instance per render. This should really be fine performance-wise.
React components defined as ES6 classes do not autobind methods' this context to the component instance. In this particular case, the renderRow callback is not bound and the context refers to the global application context instead, so the reference to this.imageTouched is undefined.
A common pattern you see a lot is to bind the callbacks in your render method:
<ListView
renderRow={this.renderRow.bind(this)}
/>
This, however, has the effect of creating a new instance of the function on every render, which causes unnecessary work for the garbage collector.
Another alternative is to use (lexically scoped) arrow functions and call the methods explicitly:
<ListView
renderRow={(data) => this.renderRow(data);
/>
But this has the same unwanted effect of unnecessarily creating functions on every render.
A slightly more verbose, but more "correct" way is to bind the callbacks in the class constructor:
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
}
Try this
<TouchableHighlight onPress={() => this.imageTouched()}>
Make sure to bind renderRow
renderRow={this.renderRow.bind(this)}
I am using Alloy 1.3. Can the content in the Controller.getView() can be updated? For example:
In Alloy, if we have view view.xml
<Alloy>
<View>
<Label id="label1"/>
... other content ...
</View>
</Alloy>
In view.js
exports.updateLabel = function(value){
$.label1.text = value;
}
If I have another controller e.g. index.js
var v = Alloy.createController('view').getView();
// assume $.win is the <Window> in index.xml
$.win.add(v);
function updateContent(value){
// This is not work. I want to know how it can be updated
// after the controller turned into a view
v.updateLabel(value);
}
Updating content on object returned from controller.getView() method is fine. In your view.js example you can change label1 text in two different ways:
exports.updateLabel = function(value){
$.label1.text = value;
}
or
exports.updateLabel = function(value){
$.getView('label1').text = value;
}
If you are calling $.getView() without any parameters it will return top level view which has the same id as name of your controller and view.
I have a situation where I am wanting to observe the behavior of a view model as I am populating a form. I can do this with defining a lot of fields that look kind of like the model, and binding to them, but that is kind of messy.
I am currently accomplishing this with the following code;
(function ($) {
$.printJSON = function(value){
return JSON.stringify(value, undefined, 2);
}
})(jQuery);
var viewModel = kendo.observable({
// other fields etc
update: function (e) {
e.preventDefault();
$("#json_result").html($.printJSON(this));
}
});
<div style="width: 400px; float: left; padding-left: 15px;" >
<button data-bind="click: update" value="Update" >Update</button>
<pre id="json_result">
</pre>
</div>
So you click the button, and it runs the function to draw the view model JSON to the screen, all nice and formatted.
But this still requires a button click. While that isn't that big of a problem for me, since this isn't something I need for a lot of situations, is there any way to actually do this and have it update when the view model changes in any way? I tried to just bind to the function and it never updates without an explicit call, I tried binding right to the view model, and that didn't work either.
You could either simply bind the change event:
viewModel.bind("change", function (e) {
$("#json_result").html($.printJSON(this));
});
or you could use a calculated field:
var viewModel = kendo.observable({
field1: "field1",
field2: "field2",
field3: "field3",
print: function () {
// need to register for all fields so that the change event for print is triggered
for (var fieldName in this) {
if (this.hasOwnProperty(fieldName)) {
this.get(fieldName);
}
}
return $.printJSON(this.toJSON());
}
});
and bind to it with:
<pre data-bind="html: print">
See fiddle demonstrating both methods: http://jsfiddle.net/lhoeppner/S2WeB/
i'm changing a innter html of a dom element with a button. And when button is clicked i want to fire another controller function. Something like that. ... But is not working :).
$scope.addBtn = function() {
$('domtarget').html('<button ng-click="removeButton();"></button>');
}
$scope.removeBtn = function() {
$('domtarget').html('');
}
Please suggest fix :)
Do not modify DOM inside your controller, ever.
<div ng-show="showMe"></div>
<button ng-click="showMe = !showMe;anotherAction()">Switch</button>
<button ng-click="someOtherAction()">Switch2</button>
.
function SomeCtrl($scope) {
$scope.showMe=true;
$scope.anotherAction = function () {
alert("gotcha");
};
$scope.someOtherAction = function () {
$scope.showMe = !$scope.showMe;
$scope.anotherAction();
};
}
For hiding/showing an element conditionally, use ng-show or ng-hide.
For firing an event on click, use ng-click