key as variable when accessing javascript dictionary - javascript

i am trying to store css values for transformations of multiple divs in a dictionary
to access them when the div is clicked (the div id being the key of the dict).
my dictionary:
css_dict = {
'keyA' : ['10px, 15px', '20px', '10px'],
'keyB' : ['20px, 30px', '10px', '20px'],
'keyA' : ['30px, 55px', '25px', '30px'],
}
i need to access it like this (variable instead of the key):
css_dict.var[0]
jsFiddle of what im trying to do:
http://jsfiddle.net/tKFka/25/
i cant figure out or find the right syntax for this to work...

Use [] instead of dot.
var var1 = 'keyA';
css_dict[var1][0];

Related

React - syntax for passing computed styles to a div

I'm very new to the language of react. I seem to continuously get an unexpected token error on the ":". What exactly is the syntax for putting multiple styles inside the Box component shown below? Alongside that, how does one go about putting multiple of these Box components, each one having its margin changed and put inside of an array, displayed on a website.
ncaught SyntaxError: /Inline Babel script: Unexpected token, expected "}" (51:73)
const Box = (props) => <div style={"margin-left" : props.spacing, "width" : props.width, "height" : props.height, "background-color" : props.color}></div>
|
^
The box component takes multiple sub-components such as margin-left (I'm not even sure if I can use this within React) and so on. I then have a for loop that continuously adds box components to an array each with a different margin so that it ends up really displaying a row of different elements inside the div.
class StoryPage extends React.Component {
render(){
const Box = (props) => <div style={"margin-left" : props.spacing; "width" : props.width; "height" : props.height; "background-color" : props.color;}></div>
const val = 0
const boxArray = []
for(let i = 0; i < 10; i++){
val += 100
boxArray.push(<Box spacing = {val} width = "100px" height = "100px" color = "black" />)
}
return(
<div>
{boxArray}
</div>
)
}
}
What I essentially expect to happen is have the array of box elements be displayed. However, I'm not really sure how I'm supposed to go about doing this.
Your “passing an object literal as a prop”-syntax is wrong — explanation below.
React props are passed as follows:
string literal
<Component strProp='hello' />
// or
<Component strProp={'hello'} />
variable
<Component strProp={this.props.foo} />
array literal
<Component arrProp={[1, 2, 3]} />
object literal
<Component objProp={{foo: 'bar'}} />
See the double curly-brackets? One pair is needed to enclose any non-string-literal expression passed as prop, and the other is simply part of the object literal notation.
In contrast, this:
<Component objProp={foo: 'bar'} /> // <- WRONG
would not work because foo: 'bar' is not an expression.
Hugo is right. Also you don't want to add larger margin lefts to each element, margin-left specifies distance from border to element on the left. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model
You can set the property display to "inline" on all your divs to change the layout of divs from block to inline. Or just not do anything and they'll still all display.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flow_Layout
Your problem is this line:
const Box = (props) => <div style={"margin-left" : props.spacing; "width" : props.width; "height" : props.height; "background-color" : props.color;}></div>
You have provide wrong style attribute, you need to provide like this:
const Box = (props) => (
<div
style={{
marginLeft: props.spacing,
width: props.width,
height: props.height,
backgroundColor: props.color
}}
/>
);
Notice that style attribute should contain double curly braces and should separate properties with a comma ,
Demo
Note: In React, inline style name should be in camelCase.
For Example,
margin-left should be marginLeft.
background-color should be backgroundColor.

How to enact styles with React.js

I am trying to use inline styles with React.js, but I keep running into errors:
In my render function, I have:
render: function() {
var style = this.state.submitted ? {{"backgroundColor": "#1abc9c", "opacity": "0.6"}} : {{}};
return (
<div>
<h1 className="home-two-question" style={style}>{text}</h1>
</div>
)
},
Basically I want to toggle this style on click. However, when I run this, I get an error from React.js. What is the correct syntax for inline styles in React.js? Thank you!
In this line:
var style = this.state.submitted ? {{"backgroundColor": "#1abc9c", "opacity": "0.6"}} : {{}};
you're just in plain JavaScript, not inside of a JSX tag. Thus, you just want to use single {}, not double {{}}:
var style = this.state.submitted ? {"backgroundColor": "#1abc9c", "opacity": "0.6"} : {};
In particular, when you do something like:
<div style={{"backgroundColor": "white"}}>
There is one set of {} to denote that the value of the style prop should be interpreted as JavaScript, and another set of {} to denote that you are constructing an object within that value.

jqxTree: Changing font color after initialization

I have a JSON jqxTree that is being rendered properly (with Label, id, value, etc). And I have a list of ids that need to be colored differently when the tree get rendered. I was thinking, that after the tree initializes I should traverse the tree and set the style for each element's id that I have in the list.
The issue I am facing is that from the event initalize() that gets fired, I have no idea how to traverse it and set the style of the elements.
This is what I have so far...
var myList = ${myList};
var colorChangeList= ${colorChangeList};
$('#jqxTree').on('initialized', function (event) {
alert('initialized:' + event);
// put in logic to set labels of id's to blue
for(Item item : theTree) {
if(item.id belongsIn(colorChangeList) {
item.label.color = blue;
}
}
});
$('#jqxTree').jqxTree({
source : myList,
height : '100%',
width : '50%'
}
Please refer the below url to resolve:
http://www.jqwidgets.com/community/topic/programmatically-changing-font-color-of-labels/
Thanks!!!

Titanium Alloy ListView Nested Model Array of Tags

I am using Titanium Alloy version 3.2. I have a collection of posts in a listview. My data looks like this:
[
{ username: 'dude', imageUrl: 'url', tags: ['tag1','tag2','tag3'] },
{ username: 'wheres', imageUrl: 'url', tags: ['tag1'] },
{ username: 'my', imageUrl: 'url', tags: ['tag1','tag2','tag3','tag4'] },
{ username: 'car', imageUrl: 'url', tags: ['tag1','tag2'] }
]
And here is the xml. This works only for username and image. I can't figure out how to add the tags to each post.
<ListView id="streamListview">
<Templates>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic"/>
<Label bindId="username" class="username"/>
</View>
</ItemTemplate>
</Templates>
<ListSection id="section">
<ListItem template="template" class="list-item"/>
</ListSection>
</ListView>
And my controller code (without the tags)
var posts = [];
for (var i=0; i<data.length; i++){
var post = {
template : "template",
pic : { image : data[i].get("imageUrl") },
username : { text : data[i].get("username") }
};
posts.push(post);
}
$.section.setItems(posts);
How can I add tags (that are clickable) to the post if I am supposed to declare EVERY view in the template before hand? Each tags array in my example would need a different number of views depending on the array length. Each tag would ideally be its own UI.Label element. I believe this can be done using a TableView, but I would prefer using ListView for performance reasons.
I think I know what you need, in this case since you want to generate each item dynamically (for example, a scenario where you open your window with your ListView empty first and make an API call to get remote data and fill the ListView with said data) you will need to use ItemTemplates declared in their own controllers.
You just create a new controller like normal and in the view xml you put your ItemTemplate:
<Alloy>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic"/>
<Label bindId="username" class="username"/>
</View>
</ItemTemplate>
</Alloy>
In your tss you put all of the styles referred to each element in your template, since you didn't provide a tss example I can't tell what are your style properties, but in the tss you need to define the style of the template, for example lets say something like:
"#template": // this is the id of your template in your xml
{
width : Ti.UI.FILL,
height : '44dp',
backgroundColor : '#FFFFFF'
}
To fill your ListView with ListItems dynamically, you will need to do something like this in your callback from your API:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var tmp = {
pic : {
image : items[i].image
},
username : {
text : items[i].text
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
And voila, you get your ListView filled dynamically. Now there are some extra steps you can do.
In your template controller you can leave it blank since the ListView can manage the itemclick event, but if you want different actions to take place when a certain element in the Listitem to trigger, you need to specify the functions to be called in your controller for each element.
For example lets say you passed a property called dataInfo to your ImageView and your Label in your template like this:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var tmp = {
pic : {
image : items[i].image
dataInfo : items[i].fooA //lets pass to the ImageView the object fooA
},
username : {
text : items[i].text,
dataInfo : items[i].fooB //lets pass to the Label the object fooB
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
And you want the ImageView and the Label to call different functions, you will need to change your xml like this:
<Alloy>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic" onClick="imageFunction"/> <!-- added onClick event -->
<Label bindId="username" class="username" onClick="labelFunction"/> <!-- added onClick event -->
</View>
</ItemTemplate>
</Alloy>
In your controller you will declare each function:
function imageFunction(e)
{
var dataInfo;
if(Ti.Platform.osname === 'android')
{
var item = e.section.items[e.itemIndex];
var bindObject = item[e.bindId];
dataInfo = bindObject.fooA;
}
else
{
dataInfo = e.source.fooA;
}
}
function labelFunction(e)
{
var dataInfo;
if(Ti.Platform.osname === 'android')
{
var item = e.section.items[e.itemIndex];
var bindObject = item[e.bindId];
dataInfo = bindObject.fooB;
}
else
{
dataInfo = e.source.fooB;
}
}
Now you might ask, why do check for the operative system name, well that is because Android and iOS receive different e objects even if you use the same function. In iOS whatever property you pass to the source of the event can be accessed directly with e.source.propertyName while in Android you need to access to the item in e.section using e.itemIndex, after that you retrieve the view inside the item with the e.bindId associated to it.
One of the biggest restrictions on ListItems is updating the views inside a ListItem, to do this you need to update the whole item you want to change visually and assign it a different template, but the speed at which this is done you won't be able to notice any lag, seriously ListView's performance is something else, unlike ScrollView and let's not talk about the horrible and buggy TableView.
A warning, as of Titanium SDK 3.2.0.GA there's a bug in ItemTemplates that causes for views inside child views in the template to change their zIndex in Android with no way to control it, there are two known instances for this:
If you use a don't set the layout in a child view: this could cause for a view that should be displayed beneath another view to come on top of it.
If you use a vertical layout in a child view: this could cause for the positions of each view to be scrambled, this is because zIndex alters the order of display in a vertical layout.
This bug is triggered randomly and the Appcelerator team hasn't put much work on it, check the JIRA ticket here TIMOB-16704.
This can be avoided if you use a template with fixed positioned views and making sure no view comes on top of another, also remember no vertical layouts, haven't tested this with horizontal but personally I try to avoid horizontal layouts since there are other bugs related to it when used in scrollviews, normal views, etc.
EDIT
Another thing you might want to do with this is to assign a different look to the items you render, you have to options:
To apply the styles when you declare the ListItem.
To apply a different layout to each ListItem depending on a series of conditions.
For the first option you need to omit or overwrite the declaration of certain properties in your template:
For example, let's use a different background color where the property fooA exists and another color if it doesn't:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var properties = {};
if(typeof items[i].fooA !== 'undefined')
{
properties = {
backgroundColor : 'red'
};
}
else
{
properties = {
backgroundColor : 'blue'
};
}
var tmp = {
properties : properties, // properties for the template
pic : {
image : items[i].image
dataInfo : items[i].fooA //lets pass to the ImageView the object fooA
},
username : {
text : items[i].text,
dataInfo : items[i].fooB //lets pass to the Label the object fooB
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
You can change width, height, backgroundColor, layout, etc. according to your needs.
Now if you want each item to have a distinct look (meaning different views to display different content) and perhaps a different behavior, you'll need to use different templates.
This might sound bothersome but it is not, templates are fast to create once you get used to them which doesn't take long, another downer might be that if you want 11 different looks, that might mean you'll need 11 templates but that's a extreme case and you might want to rethink your UI if you're dealing with that many templates.
Although restrictive, item templates offer a wide array of options for you to use, a little of imagination is the only ingredient necessary to bring out all of the possibilities.
EDIT 2
I finally understood what was you problem, if you need to create a template whose content changes according to a x variable, then you should try declaring the template on your ListView controller, but this should be done before opening the window were you will be showing the ListView since the templates property can only be set on creation, you should add something like:
function createTemplate(items)
{
var template = {};
for(var i=0; i < items.length; i++)
{
template.childTemplates = [];
for(var j=0; items[i].tags.length; j++)
{
var childTemplate = {
type: 'Ti.UI.Label',
bindId: 'tag' + j,
properties : {
width : Ti.UI.SIZE, // Here you define how your style
height : Ti.UI.SIZE,
font : {
fontSize : '18dp'
},
text : items[i].tags[j].text // you can pass the text here or if you want to on the later for
}
};
template.childTemplates.push(childTemplate);
}
}
// After this you should end up with a template with as many childTemplates as tags each item have, so send the template to the controller with your ListView
Alloy.createController('ListViewWindow', {customTemplate: template});
}
And in your ListView controller you retrieve the template:
var args = arguments[0] || {};
var template = args.customTemplate;
$.ListView.templates = {'customTemplate' : template}; // before any window open call, do this
This should add the template to your ListView, you can also create the ListView in your controller instead of declaring it in your Alloy xml, use the one that fits your needs more.
This should be possible with a ListView if you create the template in the controller dynamically. You would also need to iterate through each "tags" object and generate a Ti.UI.Label "type" for each tag item. However, I'm not certain this method will be more efficient than using a TableView object because essentially every ListItem you create will contain a different template.
To generate a dynamic template it would be similar to this below: Keep in mind you will need to iterate over "tags" and generate x Ti.UI.Label types where x is the length of "tags". Also, the click event should work using Titanium SDK 3.2.1.
var plainTemplate = {
childTemplates: [
{
type: 'Ti.UI.Label',
bindId: 'username'
},
{
type: 'Ti.UI.ImageView',
bindId: 'pic'
},
{
type: 'Ti.UI.Label',
bindId: 'tags',
events: { click : handleTagClickEvent } // Binds a callback to click event
}
]};
function handleTagClickEvent(e) {
Ti.API.info('You clicked a tag label: ' + e.type);
}
var listView = Ti.UI.createListView({
templates: { 'plain': plainTemplate },
defaultItemTemplate: 'plain'
});
Hope this helps you in some way!

How to use animateProperty for TextBox background highlight?

I'm trying to animate a property (backgroundColor) of a dijit/form/TextBox. I was starting to pull my hair out when this wasn't working:
var node = dom.byId("myTextBox");
fx.animateProperty( {
node : node,
duration : 750,
properties : {
backgroundColor : {
start : "yellow"
}
}
}).play();
However, this works:
var node = dom.byId("myTextBox");
fx.animateProperty( {
node : node.parentNode.parentNode, // grandparent of "myTextBox"
duration : 750,
properties : {
backgroundColor : {
start : "yellow"
}
}
}).play();
Is that how it's supposed to work? The examples on this page don't need to, but none are using a TextBox either.
Side question: Is there a more direct equivalent to JQueryUI's highlight effect? That's what I'm going for.
It would probably be better for you to get a reference to your widget object with dijit.byId("myTextBox") instead. Then you can just reference myTextBox.domNode or myTextBox.focusNode depending on what you are trying to highlight. I'm not sure if you want the actual text input area to be highlighted or the background, but this simple jsfiddle demonstrates both. Your code would be changed to something like:
var textbox = dijit.byId("myTextBox");
fx.animateProperty( {
node : textbox.focusNode // If you are trying to highlight the input background
duration : 750,
properties : {
backgroundColor : {
start : "yellow"
}
}
}).play();

Categories