Ionic using multiple chart.js canvas in the same page - ionic-framework

Does anyone have an example for using multiple canvas in the same page?
I have something like this in the HTML:
<div style="height: 138px" *ngFor="let item of listItems; let i = index">
<canvas #pieCanvas id="pieCanvas{{i}}" style="width: 100px !important; height: 100px !important"></canvas>
</div>
In the .ts file:
#ViewChild("pieCanvas") pieCanvas: ElementRef;
for (var j = 0; j < chartcount; j++)
{
let htmlRef = document.getElementById('pieCanvas'+j);
this.pieCanvas = new Chart(htmlRef, piechartdata);
}
Getting always null is not an object (evaluating 'item.length') error.
With only one chart it works perfect, but there I use sth. like
this.barCanvas = new Chart(this.barCanvas.nativeElement......
I Googled, but couldn't find a solution.
Thanks for your help!

I have found the solution....finally!!!
In html:
<canvas #barCanvas id="barCanvaslist{{i}}"></canvas>
Then in ts:
#ViewChildren('barCanvas') Canvaslist: QueryList;
charts: any;
and afterwards:
this.Canvaslist.changes.subscribe(c =>
{ c.toArray().forEach(item =>
{
this.Canvaslist = new Chart(item.nativeElement, pieData[j]);
j = j+1;
})
});
this does the trick

Related

Convert Excel form window to Google Sheets window

As you've probably found, there appears to be no equivalent way to add the following Excel form and associated VBA code to Google Sheets or Scripts or Forms:
Is there some add-in that can be used to pop up this image and its controls? This has to be used many times in an accounting sheet to categorize expenditures at tax time.
It may not look exactly the same but I was able to construct a custom dialog in a short period of time to show how HTML service can be used to produce similar results.
First I construct an HTML template that contains the 2 combo boxes with multiple lines.
HTML_Test.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('CSS_Test'); ?>
</head>
<body>
<div id="left">
<label for="expenseCategory">Expense Category</label><br>
<select id="expenseCategory" size="10">
</select>
</div>
<div id="middle">
<label for="expenseSubCategory">Expense Sub Category</label><br>
<select id="expenseSubCategory" size="10">
</select>
</div>
<?!= include('JS_Test'); ?>
</body>
</html>
Then a CSS file to contain all my element formatting.
CSS_Test.html
<style>
#expenseCategory {
width: 90%;
}
#expenseSubCategory {
width: 90%;
}
#left {
width: 25%;
float: left;
}
#middle {
width: 50%;
float: left;
}
</style>
And a javascript file for client side javascript. I've simply hard coded some data to show how the select elements are filled in but this could just as easily be done using template scripting, or google.script.run
<script>
var expenses = [["A","1","2","3"],
["B","4","5"],
["C","6","7","8","9","10"]
];
function expenseCategoryOnClick() {
try {
let expenseCategory = document.getElementById('expenseSubCategory');
expenseCategory.options.length = 0;
expenses[this.selectedIndex].forEach( (expense,index) => {
if( index > 0 ) {
let option = document.createElement("option");
let text = document.createTextNode(expense);
option.appendChild(text);
expenseCategory.appendChild(option);
}
}
);
}
catch(err) {
alert("Error in expenseCategoryOnClick: "+err)
}
}
(function () {
// load first expense
let expenseCategory = document.getElementById('expenseCategory');
expenseCategory.addEventListener("click",expenseCategoryOnClick);
expenses.forEach( expense => {
let option = document.createElement("option");
let text = document.createTextNode(expense[0]);
option.appendChild(text);
expenseCategory.appendChild(option);
}
);
expenseCategory = document.getElementById('expenseSubCategory');
expenses[0].forEach( (expense,index) => {
if( index > 0 ) {
let option = document.createElement("option");
let text = document.createTextNode(expense);
option.appendChild(text);
expenseCategory.appendChild(option);
}
}
);
}
)();
</script>
Then there is the server side code bound to a spreadsheet.
Code.gs
function onOpen(e) {
var menu = SpreadsheetApp.getUi().createMenu("Test");
menu.addItem("Show Test","showTest");
menu.addToUi();
}
// include(filename) required to include html files in the template
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
function showTest() {
var html = HtmlService.createTemplateFromFile("HTML_Test");
html = html.evaluate();
html.setWidth(800);
SpreadsheetApp.getUi().showModalDialog(html,"Test");
}
The dialog looks like this. Many more html elements can be added as needed. This just shows the basics. This may be more difficult than an wysiwig html editor but I find I have better control of the appearance and function of my pages this way. Notice I clicked "C" and the sub category is filled in automatically.

How to use autocomplete on search bar on Ionic 4?

I'm looking for some example but cannot see anyone googling it, just what i want is to hardcode 2 or 3 words, thank you so much. Do i have to look for on ionic 3? or in angular2 better?
In your html file:
<ion-searchbar type="text" debounce="500" (ionChange)="getItems($event)"></ion-searchbar>
<ion-list *ngIf="isItemAvailable">
<ion-item *ngFor="let item of items">{{ item }}</ion-item>
</ion-list>
in your ts file:
// Declare the variable (in this case and initialize it with false)
isItemAvailable = false;
items = [];
initializeItems(){
this.items = ["Ram","gopi", "dravid"];
}
getItems(ev: any) {
// Reset items back to all of the items
this.initializeItems();
// set val to the value of the searchbar
const val = ev.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() !== '') {
this.isItemAvailable = true;
this.items = this.items.filter((item) => {
return (item.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
} else {
this.isItemAvailable = false;
}
}
Mohan Gopi's answer is complete, but in order to make use of the debounce attribute, you have to use the ionChange event instead of the ionInput event.
<ion-searchbar type="text" debounce="500" (ionChange)="getItems($event)"></ion-searchbar>
...
...
That way the event will trigger after the user stops typing (after 500 milliseconds have passed since his last key press), instead of whenever a key is pressed.
Just wanted to share something I tried myself. I have implemented the autocomplete from Angulars material design (https://material.angular.io/components/autocomplete/overview)
But it did not look exactly as the rest of the ionic input components. I also tried the ion-searchbar but I did not like the search input, I wanted a normal ion-input So I did this:
html:
<ion-list>
<ion-item>
<ion-label position="floating">Supplier*</ion-label>
<ion-input (ionChange)="onSearchChange($event)" [(ngModel)]="supplier"></ion-input>
</ion-item>
<ion-item *ngIf="resultsAvailable">
<ion-list style="width: 100%; max-height: 200px; overflow-y: scroll;">
<ion-item *ngFor="let result of results" (click)="supplierSelected(result)" button>
<ion-label>{{result}}</ion-label>
</ion-item>
</ion-list>
</ion-item>
</ion-list>
in component.ts:
resultsAvailable: boolean = false;
results: string[] = [];
ignoreNextChange: boolean = false;
onSearchChange(event: any) {
const substring = event.target.value;
if (this.ignoreNextChange) {
this.ignoreNextChange = false;
return;
}
this.dataService.getStrings(substring).subscribe((result) => {
this.results = result;
if (this.results.length > 0) {
this.resultsAvailable = true;
} else {
this.resultsAvailable = false;
}
});
}
supplierSelected(selected: string) :void {
this.supplier = selected;
this.results = [];
this.resultsAvailable = false;
this.ignoreNextChange = true;
}
Granted the question was about ion-searchbar but maybe somebody out there also wants to use a normal ion-input like me. There is no clear icon but I can live with that, or just add one next to the ion-input. Could be that there is a way to turn the ion-searchbar into a normal ion-input style? Can't find it though in the docs.

Leaflet map in modal

I have this modal in my index.html:
<div id="myModal" class="modal">
<span class="close1">×</span>
<div id="mapImage1"></div>
<div id="caption"></div>
</div>
The <div id="mapImage1"> is the leaflet map <div>
Then I have the function, which should load the Leaflet map into the modal. The parameter image is the image which I would like to show on the leaflet map.
function modalImage(modal,image,modalDiv,text,close) {
// Get the modal
var modal = document.getElementById(modal);
var img = document.getElementById(image);
var modalDiv = document.getElementById(modalDiv);
console.log(modalDiv);
var captionText = document.getElementById(text);
img.onclick = function () {
modal.style.display = "block";
initLeafletimage(modalDiv,img);
captionText.innerHTML = this.alt;
}
// Get the <span> element that closes the modal
var span = document.getElementsByClassName(close)[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function () {
modal.style.display = "none";
}
}
The map itself is generated by this code:
function initLeafletimage(map,image){
console.log(image.src)
var imgDimensions={width:300, height:300} //this is the height and width of the image. It hasn't been loaded yet.
var map = L.map(map, {
maxZoom: 24,
minZoom: -24,
crs: L.CRS.Simple
}).setView([imgDimensions.height/2, imgDimensions.width/2], 0);
var imageUrl = image.src;
var imageBounds = [
[imgDimensions.width , 0],
[0, imgDimensions.height]
];
L.imageOverlay(imageUrl, imageBounds).addTo(map);
}
modalImage('myModal','left','mapImage1','caption','close1');
The map is not even showing up in the modal.
What have I missed?
Unfortunately, like #ghybs pointed out, I missed to define the height and width of the map div. That is why no map was present. With this css it works perfectly:
#mapImage1{
height: 100%;
width: 100%;
position: fixed;
}

Ionic 3 using ion-checkbox for only select one

How can I using checkbox for select one (just like radio), my code:
<div *ngFor="let address of addresses; let i = index;">
<ion-item>
<ion-checkbox id="cb_{{address.id}}" (ionChange)="selectedAddress(address.id,addresses,i)" checked="false"></ion-checkbox>
</ion-item>
</div>
in ts file:
selectedAddress(id,addresses,index){
for(let i=0; i<addresses.length; i++){
if(index != i){
document.getElementById("cb_"+addresses[i].id).checked = false;
}
}
}
but it is not working, anyone know how to achieve it? thanks a lot
Bind address.checked = false; kind thing when page is loading using for loop or using the API.
pass address object trough
selectedAddress(address,addresses,i) method.
in.ts
selectedAddress(address,addresses,i)
{
address.checked = !address.checked;
}

Change contents based on single function

Javascript. The following code works, but I have to call the function 3 times.
Should I be using replaceChild()?
This is what I have so far:
<!DOCTYPE html>
<html>
<body>
<ul id="myList1"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
<ul id="myList2"><li>a</li><li>b</li><li>c</li><li>d</li></ul>
<p id="demo">Click the button to move an item from one list to another</p>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction()
{
var tmp = 5;
for(var i = 0; i < tmp; i++)
{
var node=document.getElementById("myList2").getElementsByTagName("LI")[i];
document.getElementById("myList1").appendChild(node);
var node2=document.getElementById("myList1").getElementsByTagName("LI")[i];
document.getElementById("myList2").appendChild(node2);
}
}
</script>
</body>
</html>
You don't need to replace anything, just move nodes with appendChild Something like this:
function myFunction() {
var list1 = document.getElementById("myList1"),
list2 = document.getElementById("myList2"),
length1 = list1.children.length,
length2 = list1.children.length;
while (list1.children.length) {
list2.appendChild(list1.children[0]);
}
while (list2.children.length > length2) {
list1.appendChild(list2.children[0]);
}
}
Demo: http://jsfiddle.net/dfsq/4v94N/1/