Titanium Alloy: Run a function that exists in a require statement - titanium

I have the following code:
index.xml
<Window>
<View>
<Require id="foo1" src='foo'>
</View>
</Window>
foo.xml
<View>
<Label>This is from foo</Label>
</View>
foo.js
function doSomething() {
Ti.API.info('YES!');
}
Question
I want to be able to run the function doSometing() in index.js. How can I do that?
I tried:
$.foo1.doSomething()
But that does not seem to work.

<Window>
<View>
<Require id="foo1" src='foo'>
</View>
</Window>
In this code, Require id holds the controller of foo.js file, means,
$.foo1 = $ in foo.js
In order to access any property or method from Require, you can attach that property to any view or just export it like this:
foo.js
$.doSomething = function () {
Ti.API.info('YES!');
}
index.js
$.foo1.doSomething();
In case of above #miga's answer, you need to use this code in index.js :
// view is the id of topmost view to which you attached the method.
$.foo1.view.doSomething();

foo.xml
<View id="view">
<Label>This is from foo</Label>
</View>
foo.js
$.view.doSomething = function(){
Ti.API.info('YES!');
}
And then: $.foo1.view.doSomething();
edit: better
exports.doSomething = function(){
Ti.API.info('YES!');
}
to use it without the .view!

Related

How do I bind a local function when I pass a rendered view interacting with that function to a prop in react-native?

I'm passing a render to the Accordion element in native-base using the renderContent prop. The render contains two buttons, which, when pressed, run functions that are local to the current component. Unfortunately those functions are not available once it has been actually rendered.
How do I bind the functions properly so that when pressed, the correct functions are referenced?
I'm using the most modern stable releases of react-native, native-base, and I'm running this through expo for testing.
Here's the documentation on native-base:
http://docs.nativebase.io/Components.html#accordion-custom-header-content-headref
Accordion:
<Accordion
dataArray={ this.state.websites }
renderContent={ this._renderAccordionContent }
/>
renderContent:
_renderAccordionContent(content) {
return (
<Button
onPress={() => this.openSite(content.path)}
>
<Text>Open</Text>
</Button>
<Button
onPress={() => this.editSite(content.key)}
>
<Text>Edit</Text>
</Button>
)
}
When the buttons are pressed, the expected results are that the functions are run.
The actual results are that when the buttons are pressed, these errors are populated:
_this2.openSite is not a function.
_this2.editSite is not a function.
Thank you for any help.
Check out this excellent article that shows several different ways of binding your functions https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56
Here is an example of binding it in the constructor of your component that uses the Accordion component. It is by no means the only way of binding the functions. The above article gives 5 different ways of doing it.
class MyComponent extends Component {
constructor(props) {
super(props);
this.openSite = this.openSite.bind(this);
this.editSite = this.editSite.bind(this);
}
// I am assuming you have written your functions like this and not as arrow functions
openSite (path) {
...
}
editSite (key) {
...
}
_renderAccordionContent(content) {
return (
<Button
onPress={() => this.openSite(content.path)}
>
<Text>Open</Text>
</Button>
<Button
onPress={() => this.editSite(content.key)}
>
<Text>Edit</Text>
</Button>
)
}
render() {
...
<Accordion
dataArray={ this.state.websites }
renderContent={ this._renderAccordionContent }
/>
...
}
}

Injecting Custom JavaScript Into React Native's Webview

I want to inject javascript codes to injectedJavaScript method of react native web view. I could inject one javascript code working fine but multiple can't. Is there any trick to do that?
injectedJavaScript={`document.querySelector('.header-wrapper').style.display='none' ` }
this works.
But i want something like this to inject multiple javasript things but not work.
let jsCode = `(
function() {
document.querySelector('.footer').style.display='none' ;
document.querySelector('.tabs').style.display='none' ;
document.querySelector('.header-wrapper').style.display='none' ;
document.querySelector('.wrapper').style.margin-top=-70px ;
})();`;
render() {
return (
<WebView
source={{uri: 'blabla.com'}}
style={{marginTop: 20}}
injectJavaScript={jsCode}
javaScriptEnabledAndroid={true}
/>
);
}
When i try this i am getting unexpected token etc. How could i inject multiple javascripts to react native web view ? Thanks in advance.
Full code :
import React from 'react';
import { StyleSheet, Text, View,WebView } from 'react-native';
export default class App extends React.Component {
render() {
return (
<WebView
source={{uri: 'https://trends.google.com/trends/trendingsearches/daily?geo=TR'}}
injectedJavaScript={`document.querySelector('.trending-searches-footer').style.display='none';`
+ ` document.querySelector('.content-header-buttons daily-header-buttons').style.display='none'; `
+ ` document.querySelector('.trending-feed-tabs').style.display='none'; `
+ ` document.querySelector('.header-wrapper').style.display='none'; `
+ ` document.querySelector('.trending-feed-page-wrapper').style.marginTop='-70px'; `
}
javaScriptEnabled={true}
ref="WEBVIEW_REF"
/>
);
}
}
You have an error in your javascript, this would cause the script to fail:
document.querySelector('.wrapper').style.margin-top=-70px; // this is wrong syntax
try this
document.querySelector('.wrapper').style.marginTop='-70px';
To use it with injectedJavascript write your script as you would if it was one line, it doesn't make any difference, but you should make sure that your javascript doesn't have any errors:
let jsCode = `
document.querySelector('.footer').style.display='none';
document.querySelector('.tabs').style.display='none';
document.querySelector('.header-wrapper').style.display='none';
document.querySelector('.wrapper').style.marginTop='-70px';
`;
And the use injectedJavaScript and not injectJavaScript to use it.
<WebView
source={{uri: 'blabla.com'}}
style={{marginTop: 20}}
injectedJavaScript={jsCode}
javaScriptEnabledAndroid={true}
/>

React Native hangs when I create a child component

Sorry for the dummy question, but I'm really stuck.
I created a very simple react-native app using these instructions.
Then I changed App.js to be
import React from 'react';
import {AppRegistry, Button, View } from 'react-native';
class RootView extends React.Component {
state = {
showFoo: false,
}
showFoo = () => {
this.setState({showFoo: true})
}
renderFoo = () => {
if (this.state.showFoo) {
console.log("at 4");
const item = <View />; /// BOOM!
console.log('at 5', item);
return item;
}
return null;
}
render = () => {
const renderFoo = this.renderFoo();
return (
<View>
<Button title="Press Me" onPress={this.showFoo} />
</View>
);
}
}
export default RootView;
Now, if I launch it using the Expo client on my Android 6.0.1. and I press "Press Me" button, it hangs and doesn't respond to back button.
In adb logcat, I can see "at 4", but never "at 5". It is like it stucks at "BOOM!" line for some reason (a dead lock?).
Wondering if I'm doing something wrong? My apologies again, but I have already spent a fair amount of time on this, would really appreciate any clue. Also, how could I debug things like that one?
Versions of react dependencies:
"dependencies": {
"expo": "^27.0.1",
"react": "16.3.1",
"react-native": "~0.55.2"
}
}
(Please let me know if you feel the question needs more details in the comments, I'm happy to update it.)
You should either use
<Button title="Press Me" onPress={this.showFoo.bind(this)}/>
or use
<Button title="Press Me" onPres{()=>this.showFoo()}/>
and also call this.renderFoo(); inside render method, with this syntax
{this.renderFoo()}
I've created a snack to show you the solution.
The problem is with your render method
render = () => {
const renderFoo = this.renderFoo();
return (
<View>
<Button title="Press Me" onPress={this.showFoo} />
</View>
);
}
Specifically const renderFoo = this.renderFoo();. For this line of code, you only execute the renderFoo method and store it into renderFoo variable, and it's not within the return portion. In other words the <View /> returned by renderFoo will not show on the screen.
The fix is by the below code
render() {
return (
<View>
<Button title="Press Me" onPress={this.showFoo} />
{this.renderFoo()}
</View>
);
}
Finally, after hours of investigation...
As it appears, the problem was this line:
console.log('at 5', item);
It hasn't actually stuck. If I waited for 5+ seconds, the app proceeded. Seems like logging a react component is a very expensive operation.
Same problem I had when I was trying to log some lambda function.
TLDR: don't log complex objects!!!!
React native for android run very slow when not enable "Debug JS"
https://facebook.github.io/react-native/docs/performance.html#using-consolelog-statements

Implement Hero animation like shoutem About extension

I try to implement the hero animation like in the shoutem About extension. Basically, I add animationName to NavigationBar and the Image like in the extension. I also had to add ScrollDriver because it would error-ed otherwise. But it seems the NavigationBar does not pass the driver down to its child components, so I still got this error. Is it possible to implement the hero animation like what was demonstrated here? https://medium.com/shoutem/declare-peace-with-react-native-animations-e947332fa9b1
Thanks,
import { ScrollDriver } from '#shoutem/animation';
getNavBarProps() {
const driver = new ScrollDriver();
return {
hasHistory: true,
driver: driver,
title: 'Title',
navigateBack: () => this.props.navigation.dispatch(NavigationActions.back()),
styleName: 'fade clear',
animationName: 'solidify',
};
}
render () {
const driver = new ScrollDriver();
return (
<Screen styleName=" paper">
<View style={{height:68}}>
<NavigationBar {...this.getNavBarProps()} />
</View>
<ScrollView style={styles.container}>
<Image
styleName="large"
source={require('../Images/spa2.jpg') }
defaultSource={require('../Images/image-fallback.png')}
driver={driver}
animationName="hero"
/>
...
I'm the author of the article, from you question, I'm not sure are you trying to create an extension on shoutem or you just want to recreate animation in any other React Native app.
If you are creating an extension or CardStack from #shoutem/ui/navigation, you don't event need to care for ScrollDriver. It would be pushed throught the context to the ScrollView (imported from #shoutem/ui) and NavigationBar (imported from #shoutem/ui/navigation).
If you are creating your own React Native project to be able to do it like in article I suggest the following. At the root component of your app:
import ScrollView from '#shoutem/ui';
class App extends Component {
...
render() {
return (
<ScrollView.DriverProvider>
<App />
</ScrollView.DriverProvider>
);
}
}
Then you don't have to take care of initialization of ScrollDriver on each screen, if you use our components and a ScrollView it will push the driver where it needs to be. :) So your screen at the end would look like this:
import {
ScrollView,
NavigationBar,
Image
} from '#shoutem/ui';
class MyScreen extends Class {
render() {
return (
<Screen>
<NavigationBar animationName="solidify" />
<ScrollView>
<Image animationName="hero" />
</ScrollView>
</Screen>
);
}
}
The whole working example is here https://github.com/shoutem/ui/tree/develop/examples/RestaurantsApp/app

Use <Image> with a local file

The documentation says that the only way to reference a static image is to use require.
But I'm not sure where does react expect to have those images. The examples don't have any domain, so it seems like you have to go to Xcode and add them to Images.xcassets, but that didn't work for me.
Using React Native 0.41 (in March 2017), targeting iOS, I just found it as easy as:
<Image source={require('./myimage.png')} />
The image file must exist in the same folder as the .js file requiring it for "./" to work.
I didn't have to change anything in the XCode project. It just worked.
Note that the path seems to have to start with "./" or "../" and be full lower case. I'm not sure what all the restrictions are, but start simple and work forward.
Hope this helps someone, as many other answers here seem overly complex and full of (naughty) off-site links.
UPDATE: BTW - The official documentation for this is here:
https://reactnative.dev/docs/images
It works exactly as you expect it to work. There's a bug https://github.com/facebook/react-native/issues/282 that prevents it from working correctly.
If you have node_modules (with react_native) in the same folder as the xcode project, you can edit node_modules/react-native/packager/packager.js and make this change: https://github.com/facebook/react-native/pull/286/files . It'll work magically :)
If your react_native is installed somewhere else and the patch doesn't work, comment on https://github.com/facebook/react-native/issues/282 to let them know about your setup.
ES6 solution:
import DefaultImage from '../assets/image.png';
const DEFAULT_IMAGE = Image.resolveAssetSource(DefaultImage).uri;
and then:
<Image source={{uri: DEFAULT_IMAGE}} />
If loading images dynamically one can create a .js file like following and do require in it.
export const data = [
{
id: "1",
text: "blablabla1",
imageLink: require('../assets/first-image.png')
},
{
id: "2",
text: "blablabla2",
imageLink: require('../assets/second-image.png')
}
]
In your component .js file
import {data} from './js-u-created-above';
...
function UsageExample({item}) {
<View>
<Image style={...} source={item.imageLink} />
</View>
}
function ComponentName() {
const elements = data.map(item => <UsageExample key={item.id} item={item}/> );
return (...);
}
I had this exact same issue until I realized I hadn't put the image in my Image.xcassets. I was able to drag and drop it into Xcode with Image.xcassets open and after rebuilding, it fixed the problem!
To display image from local folder, you need to write down code:
<Image source={require('../assets/self.png')}/>
Here I have put my image in asset folder.
From the UIExplorer sample app:
Static assets should be required by prefixing with image! and are located in the app bundle.
So like this:
render: function() {
return (
<View style={styles.horizontal}>
<Image source={require('image!uie_thumb_normal')} style={styles.icon} />
<Image source={require('image!uie_thumb_selected')} style={styles.icon} />
<Image source={require('image!uie_comment_normal')} style={styles.icon} />
<Image source={require('image!uie_comment_highlighted')} style={styles.icon} />
</View>
);
}
I was having trouble with react-native-navigation, I created my own header component, then inserted a image - as logo - on the left before title, then when I was triggering navigate to another screen and then back again, logo was loading again, with a timeout near 1s, my file were local. My solution :
Logo.json
{"file" : "base64 big string"}
App.js
import Logo from '.../Logo.json'
...
<Image source={{uri:Logo.file}} />
We can do like below:
const item= {
image: require("../../assets/dashboard/project1.jpeg"),
location: "Chennai",
status: 1,
projectId: 1
}
<Image source={item.image} style={[{ width: 150, height: 150}]} />
This from https://github.com/facebook/react-native/issues/282 worked for me:
adekbadek commented on Nov 11, 2015
It should be mentioned that you don't have to put the images in Images.xcassets - you just put them in the project root and then just require('./myimage.png') as #anback wrote
Look at this SO answer and the pull it references
For typescript user
import { ImageSourcePropType } from 'react-native'
type Data = {
image:ImageSourcePropType
}
const data:Data = {
image:require('../.../log.png')
}
and then
<Image source={data.image}/>
You have to add to the source property an object with a property called "uri" where you can specify the path of your image as you can see in the following example:
<Image style={styles.image} source={{uri: "http://www.mysyte.com/myimage.jpg"}} />
remember then to set the width and height via the style property:
var styles = StyleSheet.create({
image:{
width: 360,
height: 40,
}
});