Appcelerator: Multiple Subviews Syncing to Last Callback - titanium

I'm creating a custom menu with background images, styling, etc. so I created a separate menuTile view and controller and send it the background, title, and callback. If I add multiple menuTiles using the Require tag, all tiles fire the callback of the last menuTile instead of their own individual one. I'm confident there is no bug/typo in my code so maybe it's a misunderstanding of the Require tag or callbacks. Please assist.
Menu.xml, Menu.js...
<View id="vwBody">
<Require src="menuTile" id="menuTile1" />
<Require src="menuTile" id="menuTile2" />
<Require src="menuTile" id="menuTile3" />
</View>
function initializeMenuTiles() {
$.menuTile1.initialize({
backgroundImage: 'img1.jpg',
title: 'Menu Tile 1',
callback: btnMenuTile1Click,
});
$.menuTile2.initialize({
backgroundImage: 'img2.jpg',
title: 'Menu Tile 2',
callback: btnMenuTile2Click,
});
$.menuTile3.initialize({
backgroundImage: 'img3.jpg',
title: 'Menu Tile 3',
callback: btnMenuTile3Click,
});
}
MenuTile.js...
$.initialize = function(args) {
$.btnMenuTile.backgroundImage = '/images/' + args.backgroundImage;
$.btnMenuTileLabel.text = args.title;
if (args.callback) {
btnMenuTileClicked_callback = args.callback;
}
};
function btnMenuTileClick() {
if (btnMenuTileClicked_callback) {
btnMenuTileClicked_callback();
}
}
So no matter what menuTile I click, btnMenuTile3Click will always fire. If I don't provide a callback for menuTile3, then btnMenuTile2Click will always fire.

I don't see where you define btnMenuTileClicked_callback so it will then be in the module's global scope, which is shared between all instances.
Simply add this before the $.initialize... line:
var btnMenuTileClicked_callback;

Related

show block toolbar programmatically gutenberg

I am creating a block with InnerBlocks component.
If no content added to the InnerBlocks (and even with content in fact) it is very difficult to popup the block toolbar
I would like to add an iconbutton on top corner that will show the block floating toolbar
How can I tell the .block-editor-block-contextual-toolbar to show?
I don't see any method of the .wp-block in the inspector that would do that and the documentation of Block Controls: Block Toolbar and Settings Sidebar https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar/ is quite basic
Many thanks
You can use useSelect() to determine if there are any blocks present in the InnerBlocks component:
import { useSelect } from '#wordpress/data';
const hasInnerBlocks = useSelect((select) => (
select('core/block-editor').getBlock(clientId).innerBlocks.length > 0
), [clientId]);
Then you can use hasInnerBlocks to conditionally render whatever you'd like within the edit function:
{ !!hasInnerBlocks && (
<BlockControls group="block">
<ToolbarGroup
// Toolbar group settings here
/>
</BlockControls>
) }
Try to use same code structure among the edit and save methods. The RIchText need to be waraped inside div.
<div>
<RichText.Content
className={ `sticky-note-${ props.attributes.alignment }` }
style={ {
fontSize: props.attributes.fontSize,backgroundColor: props.attributes.color,
} }
tagName="p"
value={ props.attributes.content }/>
</div>
Example
I created this example to illustrate your situation.
import { InnerBlocks, BlockControls } from '#wordpress/block-editor';
// ...
edit: () => {
const blockProps = {
// your own props
};
return (
<div { ...blockProps }>
<BlockControls>
// your controls
</BlockControls>
<InnerBlocks />
</div>
);
}
Problem
For the BlockControls to decide whether or not it should appear, it needs to get some context from its parent which your own props don't have.
Solution:
Use the block props instead for the parent of BlockControls.
Steps:
Import useBlockProps from #wordpress/block-editor:
import { InnerBlocks, BlockControls, useBlockProps } from '#wordpress/block-editor';
Pass your own props as an argument to useBlockProps():
const blockProps = useBlockProps({
// your own props
});
Result
import { InnerBlocks, BlockControls, useBlockProps } from '#wordpress/block-editor';
// ...
edit: () => {
const blockProps = useBlockProps({
// your own props
});
return (
<div { ...blockProps }>
<BlockControls>
// your controls
</BlockControls>
<InnerBlocks />
</div>
);
}
Links
I hope that helped.
My answer is based on Wordpress's official Block Editor Handbook:
https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar/#block-toolbar
https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/
https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#block-wrapper-props

Twitter typeahead.js not working in Vue component

I'm trying to use Twitter's typeahead.js in a Vue component, but although I have it set up correctly as tested out outside any Vue component, when used within a component, no suggestions appear, and no errors are written to the console. It is simply as if it is not there. This is my typeahead setup code:
var codes = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('code'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: contextPath + "/product/codes"
});
$('.typeahead').typeahead({
hint: true,
highlight: true,
minLength: 3
},
{
name: 'codes',
display: 'code',
source: codes,
templates: {
suggestion: (data)=> {
return '<div><strong>' + data.code + '</strong> - ' + data.name + '</div>';
}
}
});
I use it with this form input:
<form>
<input id="item" ref="ttinput" autocomplete="off" placeholder="Enter code" name="item" type="text" class="typeahead"/>
</form>
As mentioned, if I move this to a div outside Vue.js control, and put the Javascript in a document ready block, it works just fine, a properly formatted set of suggestions appears as soon as 3 characters are input in the field. If, however, I put the Javascript in the mounted() for the component (or alternatively in a watch, I've tried both), no typeahead functionality kicks in (i.e., nothing happens after typing in 3 characters), although the Bloodhound prefetch call is made. For the life of me I can't see what the difference is.
Any suggestions as to where to look would be appreciated.
LATER: I've managed to get it to appear by putting the typeahead initialization code in the updated event (instead of mounted or watch). It must have been some problem with the DOM not being in the right state. I have some formatting issues but at least I can move on now.
The correct place to initialize Twitter Typeahead/Bloodhound is in the mounted() hook since thats when the DOM is completely built. (Ref)
Find below the relevant snippet: (Source: https://digitalfortress.tech/js/using-twitter-typeahead-with-vuejs/)
mounted() {
// configure datasource for the suggestions (i.e. Bloodhound)
this.suggestions = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: item => item.id,
remote: {
url: http://example.com/search + '/%QUERY',
wildcard: '%QUERY'
}
});
// get the input element and init typeahead on it
let inputEl = $('.globalSearchInput input');
inputEl.typeahead(
{
minLength: 1,
highlight: true,
},
{
name: 'suggestions',
source: this.suggestions,
limit: 5,
display: item => item.title,
templates: {
suggestion: data => `${data.title}`;
}
}
);
}
You can also find a working example: https://gospelmusic.io/
and a Reference Tutorial to integrate twitter typeahead with your VueJS app.

Sencha Touch 2 carousel.setItems() not working

I am trying to build a dynamic image carousel using Sencha Architect. I have a carousel added to a tab panel. The carousel is set up to read images from a store called "pictureStore." I have a function to pull images from the store and create the carousel items - I can get the images from the store but unable to create the carousel. When I try to use carouself.setItems() or carousel.add() I get an error "Object # has no method". Please take a look and let me know if my method is incorrect for creating a dynamic carousel. I appreciate your help and knowledge of how to fix
Thanks,
Function to read images and create carousel items (works up until comment below):
onMycarouselActivate: function(container, newActiveItem, oldActiveItem, options) {
Ext.getStore('pictureStore').load(function(pictures) {
var items = [];
Ext.each(pictures, function(picture) {
console.log(picture.get('image'));
if (!picture.get('image')) {
return;
}
items.push({
xtype: 'myimage',
picture: picture
});
});
//following doesn't work for adding the carousel images:
//carousel.setItems(items);
//carousel.add(items);
//carousel.items = [{html: items}];
//carousel.add(carousel.items);
//carousel.setActiveItem(0);
});
},
Sample JSON with image info
{
"test": {
"cat": {
"entries": [
{
"image": "/images/1.png"
},
{
"image": "/images/2.png"
}
]
}
}
}
Error messages when using carousel.add or carousel.setItems:
Object #<HTMLDivElement> has no method 'add'
Object #<HTMLDivElement> has no method 'setItems'
If your variable carousel has no method add or setItems then it's probably not your carousel.
To make sure of that, you can try to do console.log(carousel); to figure out what it is exactly. Also, it doesn't seem to be declared anywhere in your code...
But it's quite simple to fix. I presume you've added a event listener to your carousel that listens to the activate event and if you take a look at the documentation for this event, you can see that the first parameter sent to the callback function is the container (in this case your carousel)
So what you have to write is this :
onMycarouselActivate: function(carousel, newActiveItem, oldActiveItem, options) {
instead of this
onMycarouselActivate: function(container, newActiveItem, oldActiveItem, options) {
and you should be all set
EDIT
Also if you take a look at the documentation for the image component, you can see there is no picture in the config but there is a src attribute. SO you should write :
items.push({
xtype: 'myimage',
src: picture
});
Hope this helped
try this code
myCarousel.add({
xtype: 'image',
scr:'path of image'
});
where myCarousel is object of carousel.
You can try this, this is working for me.....
Ext.getStore('Pictures').load(function(pictures) {
Ext.each(pictures, function(picture) {
if (picture.get('image')) {
carousel.add({
html: '<img style="max-width: 100%; max-height: 100%;" src="' + picture.get('image') + '"/>'
});
}
});
});
Hope this will help you...

Sencha Touch 2.0: Universal Ext.TitleBar title not changing

I am trying to create a universal titlebar with a back button for my application. I am including it in the various views by using {xclass:mUserStories.view.titlebar}.
Here is the code for the titlebar:
Ext.define('mUserStories.view.titlebar', {
extend: 'Ext.TitleBar',
id: 'narwhal',
config: {
docked: 'top',
// id: 'narwhal',
title: 'CHW Module',
items: [{
ui: 'back',
text: 'Back',
id: 'backButton'
// hidden: true
}]
}
})
However, when I try to dynamically change the toolbar when switching to different pages, the console.log of the titlebar says the _title has changed but the text on the titlebar and the "hidden" property of the button does not change.
Here is the code for the logic that occurs when the button is pressed to switch the page:
toPage: function (arg) {
var t = Ext.getCmp('narwhal');
var b = Ext.getCmp('backButton');
console.log(t,b)
if (arg === PAGES.PATIENT_LIST) {
t.setTitle('Patient List');
b.setHidden(true)
}
Ext.getCmp('viewPort').setActiveItem(arg);
}
I have also tried to include a ref at the top for Narwhal : '#narwhal' and use var t = this.getNarwhal(), but this does not work either.
I am not sure if the problem lies with where the id is being kept, how the id is being called, or because the page is not refreshing properly. Any advice would help!
Thank you for your time :)
I have had the same situation in my project.
I managed to get everything to work like you want it by having a controller owning a reference to the title bar and listening to activeItemChange on my tabPanel.

Load html data with AJAX in Sencha touch when panel is shown

I have a TabPanel with a Tabbar and four panels inside. I want to load the HTML content for the fourth panel with an AJAX call when the panel becomes visible.
The AJAX function fetches the data from the server and places it inside the panel, which uses the panel update function. The problem is how to call this function when the panel becomes visible. A simplified version is:
Pages.Contact = new Ext.Panel({
title: 'Contact',
html: 'test data',
iconCls: 'user',
cls: 'cHome',
activate: function () {
Pages.Contact.update("my ajax data");
}
});
When I go to my panel the body content is not affected. Does anyone know what goes wrong here? I've already tried to replace activate with render and show.
To add event's listeners you need to do
listeners: {
activate: function(){
console.log('activate fired');
}
},
But that's not the event you want to listen. It's better to listen for beforecardswitch on the TapPanel object, example:
listeners: {
beforecardswitch:function(newCard, oldCard, index, anim){
if(index == 3){
//loadJson and update card.
// you may want to use this also
newCard.setLoading(true);
//and after the json request has finished set it to false.
}
}
},
The solution was to use:
beforecardswitch:function(object, newCard, oldCard, index, anim) {
As shown by Ilya139 by with the object parameter as first parameter.
Then the index variable returns the correct cardnumber.