Change image onclick-events - dart

How do I implement a button on-click event with loading different images?
I want to show different images in one div-container. If I click on the button "changeImage" it should change the picture.
How can I implement this in dart language?
Update: A new image should be loaded by each click. The images are in one file.
Do I call the img with a Button like this?
<input type="button" value="button" ng-click="img">

depending on the answer to my comment above there are different ways to do it.
(not tested)
import 'dart:async';
const NUM_IMAGES = 4;
main() {
int curImg = 1;
(querySelectorAll('img') as HtmlElement).forEach((img) {
img.onClick.listen((e) {
(querySelector('#img_${curImg % 4}') as HtmlElement).classes.add('hidden');
curImg++;
(querySelector('#img_${curImg % 4}') as HtmlElement).classes.remove('hidden');
});
}
.
<style>
img.hidden {
display: none;
}
</style>
<img id="img_1" src="a.gif" >
<img id="img_2" src="b.gif" class="hidden">
<img id="img_3" src="c.gif" class="hidden">
<img id="img_4" src="d.gif" class="hidden">
alternative solution:
List<String> uris = ['/img/img_a.gif', '/img/img_b.gif', '/img/img_c.gif', '/img/img_d.gif'];
main() {
int curImg = 0;
(imgElement = querySelector('img') as ImageElement).onClick.listen((img) {
curImg++;
imgElement.src = uris[curImg];
});
}
.
<img>

Related

Quasar: how to display an image when using q-file to pick the image?

New to Quasar & Vue.
I am using q-file which allow pick file & drag to drop file.
However, how do i display the image for preview?
Q-uploader seems work but how do i change the ui of it?
Link to component from Quasar:
https://quasar.dev/vue-components/file-picker
In you template define a q-file and q-img element. Add a #change handler and updateFile function. The q-img will contain the picture you selected.
import { ref } from 'vue';
import { defineComponent } from 'vue';
<script lang="ts">
export default defineComponent({
name: 'Component Name',
components: {},
setup () {
const image = ref(null);
const image1Url = ref('')
return {
image,
image1Url,
updateFile() {
imageUrl.value = URL.createObjectURL(image.value);
}
}
}
})
</script>
<div>
<q-file
v-model="image"
label="Pick one file"
filled
style="max-width: 300px"
#change="updateFile()"
/>
</div>
<div>
<q-img
:src="imageUrl"
spinner-color="white"
style="height: 140px; max-width: 150px"
/>
</div>
Create an #change hook on q-file:
In the script set the url from the file passed in from q-file:

removeEventListener from another array-prototype forEach

Hello, friends!
I'm new to Javascript. Using native JS.
I need when I click on the red button the blue button becomes disabled using removeEventListener. And vice versa - clicking on the blue button will add removeEventListener to the red button.
But my method does not work because the first array does not see the other array.
Thanks for the help. And, please, add comments to your code))
Here is the code and example https://jsfiddle.net/of83ycmx/
<body>
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
<script>
const box = document.querySelectorAll('.box');
const red = document.querySelectorAll('.red');
const blue = document.querySelectorAll('.blue');
red.forEach((item, i) => {
item.addEventListener('click', function redListener() {
box[i].classList.add('redBox');
//removeEventListener doesnt work because blueListener is not defined
//item.removeEventListener('click', blueListener);
});
});
blue.forEach((item, i) => {
item.addEventListener('click', function blueListener() {
box[i].classList.add('blueBox');
// item.removeEventListener('click', redListener)
});
});
</script>
made some changes that made sense to me. I am quite a beginner, so anyone who sees anything no-no or bad practice go ahead and call me out.
What should happen:
My interpretation of your explanation is this: When a user clicks on 1 of 2 buttons, the button that was NOT clicked should have its event listener removed.
Solution:
Making the functions accessible was your main problem-named functions inside of event listeners are limited to that listener (I assume). So instead move the function outside of the listener and simply call the function:
function blueListener () {
// Do stuff here
}
item.addEventListener('click', blueListener)
Now the function is accessible to the other function, so when you remove the event listener you wont get blueListener is not defined.
By wrapping the buttons and the box in a div allows you to select the button you need. Using .querySelectorAll() on the parent div allows you to select the button with the respective class (i. e the selecting the blue button when you click the red button).
The functions don't need any other info; they use this to access the clicked element. Then you can find the parent element, and select the box to change the background color, and select the respective button to remove the event listener.
DEMO:
const box = document.querySelectorAll('.box');
const red = document.querySelectorAll('.red');
const blue = document.querySelectorAll('.blue');
function redListener() {
var parent = this.parentElement;
var box = parent.querySelectorAll('.box')[0]
var blueButton = parent.querySelectorAll('.blue')[0]
box.classList.add('redBox');
blueButton.removeEventListener('click', blueListener)
}
function blueListener() {
var parent = this.parentElement;
var box = parent.querySelectorAll('.box')[0]
var redButton = parent.querySelectorAll('.red')[0]
box.classList.add('blueBox');
redButton.removeEventListener('click', redListener)
}
red.forEach((item, i) => {
item.addEventListener('click', redListener)
})
blue.forEach((item, i) => {
item.addEventListener('click', blueListener)
});
body {
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
}
.box {
width: 100px;
height: 100px;
background-color: rgb(172, 172, 172);
margin: 0px 0px 40px 0px;
display: flex;
justify-content: center;
align-items: center;
}
.redBox {
background-color: rgb(156, 56, 56);
}
.blueBox {
background-color: rgb(66, 56, 156);
}
<div class="buttons">
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
</div>
<div class="buttons">
<button class="red">Red</button>
<button class="blue">Blue</button>
<div class="box">BOX</div>
</div>

How to show Mat-dialog opening/loading indicator

I am using mat dialog to create a dialog box with 100's of input boxes. So it will take few seconds to load. I want to show a busy indicator when the dialog is loading.
Very simple code. On a button click I set a boolean to true and call dialog.open(). Then set it to false on dialogRef.afterOpened() event.
But the boolean doesnt get set to true until the dialog.open() event is completed. I can't figure out why.
StackBlitz here
https://stackblitz.com/edit/angular-d6nfhr
Enter value of say, 1000;
I am expecting the text 'Dialog opening...' (near to Add button) to appear soon after I click Add button. But it flashes for a second after the dialog is ready.
The solution does not answer the question as per the intended question but will act as a workaround solution.
Solution
Instead of showing the loading icon when loading any number of data, as per UX, it better for the user to show a limited number of input boxes and add a button that will add more input text field in a dialog box.
dialog.component.ts
#Component({
selector: 'dialog-overview-example-dialog',
templateUrl: 'dialog-overview-example-dialog.html',
})
export class DialogOverviewExampleDialog implements OnInit {
animals: any[] = [];
getTotalCountVal = null;
start: number = 0;
end: number = 20;
constructor(
public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
#Inject(MAT_DIALOG_DATA) public data: DialogData) { }
ngOnInit() {
this.getTotalCountVal = this.data.totalCount;
if (this.getTotalCountVal) {
for (let i = 0; i < this.data.totalCount; i++) {
this.animals.push('');
}
}
}
loadMore() {
if(this.end < this.getTotalCountVal) {
this.end += 20;
}
}
onNoClick(): void {
this.dialogRef.close();
}
}
dialog.component.html
<h1 mat-dialog-title>Total - {{data.totalCount}}</h1>
<div mat-dialog-content>
<p>Add favorite animals</p>
<ng-container *ngFor="let animal of animals | slice: start: end; let index=index">
<mat-form-field>
<input matInput [(ngModel)]="animal" name ="animal">
</mat-form-field>
</ng-container>
<button *ngIf="end < animals.length" mat-raised-button color="primary" (click)="loadMore()">Add more animals</button>
</div>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()">No Thanks</button>
<button mat-button [mat-dialog-close]="animals" cdkFocusInitial>Ok</button>
</div>
stackblitz working demo

Ionic Framework textarea keyboard scroll issue after Apple Testflight processing

We are using the ionic framework with iOS.
In the iOS emulator and in Safari browser, for one of our pages, clicking in a textarea shows the keyboard, and scrolls the textarea upwards so it is still viewable.
When the app is archived and processed through Apple iOS TestFlight, the behaviour is changed. Now, clicking in a textarea shows the keyboard, but the textarea no longer scrolls upwards so it is hidden.
Looks like something in the archival process is causing an issue.
Here's the code (there's another div above it). There's only the one textarea.
<div ng-if="!dy_compl">
<div class="wi-bottom item ">
<div ng-repeat="(key, dy) in element.dys">
<div id="wi-scroll-div" ng-if="key == dySel" style="height: {{scroller_height}}; overflow: scroll;">
<div>
<style>
p.wi-icon:before {
background: url("img/old_building.png") no-repeat !important;
}
</style>
<p class="wi-icon" ng-bind-html="dy.intro | to_trusted"></p>
</div>
<div ng-if="dy.ref">
<p class="wi-intro-my3" ng-bind-html="dy.ref.intro | to_trusted"></p>
<div ng-repeat="data in dy.ref.data track by $index">
<p class="wi-intro-my3-table" style="margin-left: 5%;" ng-bind-html="data | to_trusted"></p>
</div>
</div>
<label id="wi-input" class="item item-input item-stacked-label">
<span class="input-label" style="width:100%; max-width: 100%;">
<div class="wi-bottom-input-label" ng-bind-html="dy.notelabel | to_trusted"></div>
</span>
<textarea class="wi-bottom-input" ng-model="dy.note" type="text" placeholder="{{dy.note}}" ng-style="{'background-color': textAreaBackgroundColor}"></textarea>
</label>
<button class="wi-bottom-button button button-assertive col text-center" ng-click="dy.saved=true;saveNow()">
Save Notes
</button>
</br>
</div>
</div>
</div>
If you can't make it work with the plugin, check out this code I used on one project.. Looks a bit overhead, but it works:
Template:
<ion-content scroll-handle="user-profile-scroll">
<textarea maxlength="160" ng-model="currentUser.bio" ng-readonly="!editMode || focusAddInterestInput" placeholder="Write your bio..." class="user-bio">< </textarea>
</ion-content>
Controller:
$scope.windowHeight = window.innerHeight;
$scope.keyboardHeight = 0;
$scope.$on('$ionicView.loaded', function() {
var scrollView = {scrollTo: function() { console.log('Could not resolve scroll delegate handle'); }};
$timeout(function() {
var instances = $ionicScrollDelegate.$getByHandle('user-profile-scroll')._instances;
instances.length && (scrollView = instances[instances.length - 1]);
}).then(function() {
$scope.unbindShowKeyboardHandler = $scope.$on('KeyboardWillShowNotification', function(evt, info) {
$scope.keyboardHeight = info.keyboardHeight;
var input = angular.element(document.activeElement);
var body = angular.element(document.body);
var top = input.prop('offsetTop');
var temp = angular.element(input.prop('offsetParent'));
var tempY = 0;
while (temp && typeof(temp.prop('offsetTop')) !== 'undefined') {
tempY = temp.prop('offsetTop');
top += tempY;
temp = angular.element(temp.prop('offsetParent'));
}
top = top - (scrollView.getScrollPosition().top || 0);
var inputHeight = input.prop('offsetHeight');
var requiredSroll = $scope.windowHeight - $scope.keyboardHeight > top + inputHeight + 11 ? 0 : $scope.windowHeight - $scope.keyboardHeight - top - inputHeight - 12;
$timeout(function(){ scrollView.scrollTo(0, - requiredSroll || 0, true); });
});
$scope.unbindHideKeyboardHandler = $scope.$on('KeyboardWillHideNotification', function(evt, info) {
console.log(evt, info);
$scope.keyboardHeight = 0;
$timeout(function() { scrollView.scrollTo(0, 0, true); });
});
$scope.$on('$destroy', function() {
$scope.unbindShowKeyboardHandler();
$scope.unbindHideKeyboardHandler();
});
});
});
andm finally in app.js:
window.addEventListener('native.keyboardshow', keyboardShowHandler);
window.addEventListener('native.keyboardhide', keyboardHideHandler);
function keyboardShowHandler(info){
$rootScope.$broadcast('KeyboardWillShowNotification', info);
}
function keyboardHideHandler(info){
$rootScope.$broadcast('KeyboardWillHideNotification', info);
}
Turns out that we had one view that was manually disabling the keyboard scroll using:
cordova.plugins.Keyboard.disableScroll(true)
We weren't re-enabling this on a switch to another view.
The result is that in the emulator, the scroll disabling didn't traverse the scope to the new page, whereas after archival and TestFlight, it did.
Thanks for the other answers, comments.

Moving elements by dragging in Dart

I am trying to move an element using drag and drop. I want to be able to drag and element to a different location, and when I drop it, the element moves to the dropped location. Super basic, and nothing fancy. This is what I have so far:
html:
<input type='button' id='drag' class='draggable' value='drag me' draggable='true'>
Dart code:
Element drag = querySelector('.draggable');
drag.onDragEnd.listen((MouseEvent e) {
drag.style.left = '${e.client.x}px';
drag.style.top = '${e.client.y}px';
});
This doesn't quite do what I want it to do. The element is slightly off from where I drop it. I see examples in javascript with appendChild, clone(), parentNode, but none of the examples that I have seen can be reproduced in Dart. What is the best way to accomplish this? I don't want to use the DND package, since I am really trying to personally understand the concepts better.
index.html
<!doctype html>
<html>
<head>
<style>
#dropzone {
position: absolute;
top: 50px;
left: 50px;
width: 300px;
height: 150px;
border: solid 1px lightgreen;
}
#dropzone.droptarget {
background-color: lime;
}
</style>
</head>
<body>
<input type='button' id='drag' class='draggable' value='drag me'
draggable='true'>
<div id="dropzone"></div>
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
index.dart
library _template.web;
import 'dart:html' as dom;
import 'dart:convert' show JSON;
main() async {
dom.Element drag = dom.querySelector('.draggable');
drag.onDragStart.listen((event) {
final startPos = (event.target as dom.Element).getBoundingClientRect();
final data = JSON.encode({
'id': (event.target as dom.Element).id,
'x': event.client.x - startPos.left,
'y': event.client.y - startPos.top
});
event.dataTransfer.setData('text', data);
});
dom.Element dropTarget = dom.querySelector('#dropzone');
dropTarget.onDragOver.listen((event) {
event.preventDefault();
dropTarget.classes.add('droptarget');
});
dropTarget.onDragLeave.listen((event) {
event.preventDefault();
dropTarget.classes.remove('droptarget');
});
dropTarget.onDrop.listen((event) {
event.preventDefault();
final data = JSON.decode(event.dataTransfer.getData('text'));
final drag = dom.document.getElementById(data['id']);
event.target.append(drag);
drag.style
..position = 'absolute'
..left = '${event.offset.x - data['x']}px'
..top = '${event.offset.y - data['y']}px';
dropTarget.classes.remove('droptarget');
});
}
The answer above is correct, and I didn't want to edit it for that reason. However, I wanted to also offer another answer that I derived from the above. It is a lot more basic compared to the above, and so easier to follow the basic concepts for beginners. As mentioned below, I don't think you can move elements unless they are within a droppable area.
index.html:
<!DOCTYPE html>
<html>
<head>
<style>
#dropzone {
position: absolute;
top: 100px;
left: 50px;
width: 300px;
height: 150px;
border: solid 1px;
color: lightgreen;
}</style>
</head>
<body>
<div id="dropzone">
<input type='button' id='drag' class='draggable' value='drag me'
draggable='true'>
</div>
<script type="application/dart" src="main.dart"></script>
</body>
</html>
main.dart:
import 'dart:html';
main() {
Element drag = querySelector('.draggable');
Element drop = querySelector('#dropzone');
drag.onDragStart.listen((MouseEvent e) {
var startPos = (e.target as Element).getBoundingClientRect();
String xPos = "${e.client.x - startPos.left}";
String yPos = "${e.client.y - startPos.top}";
e.dataTransfer.setData('x', xPos);
e.dataTransfer.setData('y', yPos);
});
drop.onDragOver.listen((MouseEvent e) {
e.preventDefault();
});
drop.onDrop.listen((MouseEvent e) {
e.stopPropagation();
String xPos = e.dataTransfer.getData('x');
String yPos = e.dataTransfer.getData('y');
int x = num.parse(xPos);
int y = num.parse(yPos);
drag.style.position = 'absolute';
drag.style
..left = '${e.offset.x - x}px'
..top = '${e.offset.y - y}px';
});
}
I had the same question and since the answers above did not meet my needs in:
Element drag-gable by itself(No drop zone)
Reusable
For a wrapper based solution, this package could be the answer:https://pub.dartlang.org/packages/dnd
Custom element based approach(Currently cursor styling is not working):
main(){
document.registerElement('draggable-element',
DraggableElement);
querySelector('body').append(new DraggableElement()..text='draggable');
}
class DraggableElement extends HtmlElement with Draggability{
DraggableElement.created():super.created(){
learn_custom_draggability();
}
factory DraggableElement(){
return new Element.tag('draggable-element');
}
}
class Draggability{
bool __custom_mouseDown = false;
//The Coordinates of the mouse click
//relative to the left top of the
//element.
Point<int> __custom_relative_mouse_position;
void learn_custom_draggability(){
if(this is! HtmlElement ){
throw ("Draggability mixin "
"is not compatible with"
' non-HtmlElement.');
}
var self = (this as HtmlElement);
self.onMouseDown.listen(mouseDownEventHandler);
self.onMouseUp.listen(mouseUpEventHandler);
//styling
self.style.position = 'absolute';
window.onMouseMove
.listen(mouseMoveEventHandler);
}
void mouseMoveEventHandler(MouseEvent e){
if(!__custom_mouseDown) return;
int xoffset = __custom_relative_mouse_position.x,
yoffset = __custom_relative_mouse_position.y;
var self = (this as HtmlElement);
int x = e.client.x-xoffset,
y = e.client.y-yoffset;
print(x);
if(y == 0) return;
self.style
..top = y.toString() +'px'
..left = x.toString()+'px';
}
void mouseDownEventHandler(MouseEvent e){
print('mouse down');
__custom_mouseDown = true;
var self = (this as HtmlElement);
self.style.cursor = 'grabbing';
__custom_relative_mouse_position =
e.offset;
}
void mouseUpEventHandler(MouseEvent e){
print('mouse up');
__custom_mouseDown = false;
var self = (this as HtmlElement);
self.style.cursor = 'default';
}
}
Edit:
Yay, Thank you Günter Zöchbauer for informing me about reflectable. It's so small and compiles fast.
A little off the topic but posting since mixins and the below pattern goes hand in hand.
import 'package:reflectable/reflectable.dart';
class Reflector extends Reflectable{
const Reflector():
super(
instanceInvokeCapability,
declarationsCapability
);
}
const reflector = const Reflector();
#reflector
class CustomBase extends HtmlElement{
CustomBase.created():super.created(){
learn();
}
learn(){
InstanceMirror selfMirror = reflector.reflect(this);
var methods = selfMirror.type.instanceMembers;
RegExp pattern = new RegExp('^learn_custom_.*bility\$');
for(var k in methods.keys){
if(pattern.firstMatch(k.toString()) != null){
selfMirror.invoke(k,[]);
}
}
}
}
Include: "reflectable: ^0.5.0" under dependencies and "- reflectable: entry_points: web/index.dart" etc under transformers
in the pubspec.yaml and extend a custom class like the above instead of a HtmlElement and selfMirror.invoke magically calls your initializer as long as their names match the given pattern. Useful when your classes have a quite few abilities.

Resources