In my following angular application, I have multiple rows of myelement (angular directive wrapper over input tag). At a time I need to focus/select/highlight one of it, .selected class in the styles does that.
In following application, everything works fine except focus to the input tag, which needs to be bounded by the css class selected. I.E. whatever element has class selected the corresponding input tag should be focused . How can I acieve that ?
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<style>
.container {
display: flex;
flex-direction: column;
width: 600px;
}
.notebook {
display: flex;
justify-content: center;
}
.cell {
margin: 5px;
padding: 5px;
}
.selected {
border-style: solid;
border-color: green;
border-width: 1px;
border-left-width: 5px;
}
</style>
</head>
<body ng-app="myApp">
<div ng-controller="ListController as listctrl" class="notebook">
<div class="container">
<myelement ng-repeat="i in listctrl.list"
ng-click="listctrl.selected = $index"
ng-class="{selected : listctrl.selected === $index}"
class="cell"></myelement>
</div>
</div>
<script type="text/javascript">
angular
.module('myApp',[])
.controller('ListController', function($scope) {
var listctrl = this;
listctrl.list = [];
listctrl.selected = 0;
listctrl.addCell = function() {
var x = listctrl.list.length;
listctrl.list.push(x);
listctrl.selected = listctrl.list.length - 1;
}
listctrl.addCell();
$scope.$on('add', function (event, message) {
$scope.$apply(listctrl.addCell);
});
$scope.$on('keyUp', function(event) {
$scope.$apply(function(){
listctrl.selected = listctrl.selected - 1;
});
});
$scope.$on('keyDown', function(event) {
$scope.$apply(function(){
listctrl.selected = listctrl.selected + 1;
});
});
})
.directive('myelement', function($rootScope){
return {
template: '<input style="width: 95%"></input>',
restrict: 'E',
link: function (scope, element, attrs) {
var inputTag = element[0].children[0];
inputTag.focus();
element.on('keydown', function(event) {
if (event.keyCode === 13 && event.shiftKey) {
$rootScope.$broadcast('add');
} else if (event.keyCode === 38) {
$rootScope.$broadcast('keyUp');
} else if (event.keyCode === 40) {
$rootScope.$broadcast('keyDown');
}
});
},
controller: function ($scope) {
}
};
})
</script>
</body>
</html>
Consider the following example. It uses the now recommended component feature of AngularJS (since v1.5). The example is very simple so you can easily understand what is happening and how to apply it in your project.
JavaScript
class MainController {
constructor() {
this.focused = true;
}
}
class MyElementController {
constructor($element) {
this.$element = $element;
}
$onChanges(changes) {
if (changes.focused.currentValue === true) {
this.$element[0].getElementsByTagName('input')[0].focus();
}
}
}
const myElementComponent = {
bindings: {
focused: '<'
},
controller: MyElementController,
template: `<input type="text">`
};
angular
.module('app', [])
.controller('MainController', MainController)
.component('myElement', myElementComponent);
HTML
<body ng-app="app" ng-controller="MainController as vm">
<my-element focused="vm.focused"></my-element>
</body>
var elementComponent = {
bindings:{
selected:'<'
},
controller:function($element){
this.$onChanges = function(changes) {
if(changes.selected.currentValue){
$element[0].getElementsByClassName('textName')[0].focus()
}
}
},
template:'<input type="text" class="textName" style="margin:4px">'
};
var controller = function(){
this.list = [1];
this.selected = 1
this.add = function(){
var length = this.list.length ;
this.list.push(length + 1);
this.selected = length + 1;
}
};
angular.module('app', [])
.component('element', elementComponent)
.controller('appCtrl', controller);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body ng-app="app" ng-controller="appCtrl as vm" >
<script src="https://rawgit.com/angular/bower-angular/master/angular.min.js"></script>
<button ng-click="vm.add()">Add New Cell</button>
<div ng-repeat="item in vm.list" >
<element selected="item == vm.selected" ng-click="vm.selected = item"></element>
</div>
Selected Element : {{vm.selected}}
</body>
</html>
This might fill your requirement.
on every key up/done, check the class, and use focus(), blur() to change input states. in case of tab press, preventDefault()
angular
.module('myApp',[])
.controller('ListController', function($scope) {
var listctrl = this;
listctrl.list = ['1','2','3'];
listctrl.selected = 0;
listctrl.addCell = function() {
var x = listctrl.list.length;
listctrl.list.push(x);
listctrl.selected = listctrl.list.length - 1;
}
listctrl.addCell();
$scope.$on('add', function (event, message) {
$scope.$apply(listctrl.addCell);
});
$scope.$on('keyUp', function(event) {
$scope.$apply(function(){
listctrl.selected = listctrl.selected - 1;
});
});
$scope.$on('keyDown', function(event) {
$scope.$apply(function(){
listctrl.selected = listctrl.selected + 1;
});
});
})
.directive('myelement', function($rootScope){
return {
template: '<input style="width: 95%"></input>',
restrict: 'E',
scope: {},
link: function (scope, element, attrs) {
var inputTag = element[0].children[0];
var updateFocues = function(element) {
if(element[0].className.indexOf('selected') !== -1) {
scope.$apply(function() {
inputTag.focus()
});
} else {
scope.$apply(function() {
inputTag.blur()
});
}
}
element.on('keydown', function(event) {
if (event.keyCode === 13 && event.shiftKey) {
$rootScope.$broadcast('add');
} else if (event.keyCode === 38) {
$rootScope.$broadcast('keyUp');
} else if (event.keyCode === 40) {
$rootScope.$broadcast('keyDown');
}else if (event.keyCode === 9) {
event.preventDefault();
}
});
scope.$on('keyUp', function() {
updateFocues(element)
})
scope.$on('keyDown', function() {
updateFocues(element)
})
},
controller: function ($scope) {
}
};
})
.container {
display: flex;
flex-direction: column;
width: 600px;
}
.notebook {
display: flex;
justify-content: center;
}
.cell {
margin: 5px;
padding: 5px;
}
.selected {
border-style: solid;
border-color: green;
border-width: 1px;
border-left-width: 5px;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="ListController as listctrl" class="notebook">
<div class="container">
<myelement ng-repeat="i in listctrl.list"
ng-click="listctrl.selected = $index"
ng-class="{selected : listctrl.selected === $index}"
class="cell"></myelement>
</div>
</div>
</body>
</html>
Suggest you use css instead (most likely it will fit your needs). Adding extra JS code to support simple behaviours is not a good practice.
:focus selector explained on W3C
E.g.
myelement input:focus {
border-style: solid;
border-color: green;
border-width: 1px;
border-left-width: 5px;
}
Related
I was looking for the solution for my API but I couldn't find.. All examples or advices didn't work. Could somebody help me out? Or give me any suggestion? I'm still studying JQuery, so any help would be more than welcome..
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New api</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<main>
<section>
<div id="alert"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<ul id="wordblock">
</ul>
<div id="result">Result</div>
</section>
<script src="./api.js"></script>
</main>
</body>
</html>
JQuery code:
function screenResolutionAlert(x) {
if (x.matches) {
$("#alert").html("This API doesn't work with touchpads <br> (mobiles, tablets etc) <br> please use computer or laptop with a mouse").show();
} else {
$("#alert").hide();
}
}
var x = window.matchMedia("(max-width: 1200px)")
screenResolutionAlert(x)
x.addListener(screenResolutionAlert)
//API swap words code
$(function () {
$("#wordblock").sortable();
$("#wordblock").disableSelection();
const array = ["pierogi", "gołąbki", "pies", "sześcian"];
const word = array[Math.floor(Math.random() * array.length)];
let d_word = word.split('');
shuffle(d_word);
const lis = [];
for (let i = 0; i < d_word.length; i++) {
lis.push('<li class="ui-state-default">' + d_word[i] + '</li>')
}
$('#wordblock').html(lis.join(''));
$('#wordblock').mouseup(function () {
setTimeout(() => {
let r_word = '';
$('#wordblock>li').each(function (e) {
r_word += $(this).text();
});
if (r_word == word) {
$("#result").html(`Correct! It was exactly "${r_word}"`);
} else {
$("#result").html(`Wrong! keep trying.. <br> it's not "${r_word}"`);
}
}, 0);
});
});
function shuffle(a, b, c, d) {
c = a.length;
while (c) b = Math.random() * (--c + 1) | 0, d = a[c], a[c] = a[b], a[b] = d
}
Yes I was using mobile Jquery links, didn't work... And any versions of.. I tried everything what was written in the internet ;(
I tried your code and ...it seems to work! Snippet is here below, just press Run code snippet, and order letters to "PIES".
I suggest you to read about APIs, because at the moment you're not using any API at all! 😁
function screenResolutionAlert(x) {
if (x.matches) {
$("#alert")
.html(
"This API doesn't work with touchpads <br> (mobiles, tablets etc) <br> please use computer or laptop with a mouse"
)
.show();
} else {
$("#alert").hide();
}
}
var x = window.matchMedia("(max-width: 1200px)");
screenResolutionAlert(x);
x.addListener(screenResolutionAlert);
//API swap words code
$(function () {
$("#wordblock").sortable();
$("#wordblock").disableSelection();
const array = ["pies"];
const word = array[Math.floor(Math.random() * array.length)];
let d_word = word.split("");
shuffle(d_word);
const lis = [];
for (let i = 0; i < d_word.length; i++) {
lis.push('<li class="ui-state-default">' + d_word[i] + "</li>");
}
$("#wordblock").html(lis.join(""));
$("#wordblock").mouseup(function () {
setTimeout(() => {
let r_word = "";
$("#wordblock>li").each(function (e) {
r_word += $(this).text();
});
if (r_word == word) {
$("#result").html(`Correct! It was exactly "${r_word}"`);
} else {
$("#result").html(`Wrong! keep trying.. <br> it's not "${r_word}"`);
}
}, 0);
});
});
function shuffle(a, b, c, d) {
c = a.length;
while (c)
(b = (Math.random() * (--c + 1)) | 0),
(d = a[c]),
(a[c] = a[b]),
(a[b] = d);
}
ul#wordblock {
padding-left: 0;
}
ul#wordblock li {
display: inline-block;
font-size: 2em;
padding: 0.2em 0.2em;
cursor: pointer;
background-color: aliceblue;
border-radius: 50%;
margin: 0.5em;
width: 1em;
height: 1em;
text-align: center;
line-height: 0.9em;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New api</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<main>
<section>
<div id="alert"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<ul id="wordblock">
</ul>
<div id="result">Result</div>
</section>
<script src="./api.js"></script>
</main>
</body>
</html>
I want to be able to drag an element from one div into another, keeping the original where it is and making a clone in the second div. Once the cloned element is in the second div it should still be draggable.
I have implemented this twice, once with plain javascript and once using directives in Angular JS.
In the plain javascript implementation everything works as intended; a cloned object can be dragged again.
However, in the Angular JS implementation, cloned objects cannot be dragged. I'm not sure why it isnt keeping the draggable property.
Here is my code:
HTML
<!DOCTYPE html>
<head>
<title>Drag and Drop Test</title>
<!-- JQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- Bootstrap CSS CDN -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- Angular JS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<!-- Jitsi External -->
<script src="https://meet.jit.si/external_api.js"></script>
<!-- Local JS -->
<script type="text/javascript" src="../js/dragdrop.js"></script>
<!-- Local CSS -->
<link rel="stylesheet" href="../css/dragdrop.css">
</head>
<body ng-app="myApp">
<div>
<div class="dragdrop-panel" id="drag-from-div">
<h1>Icons</h1>
<div id="dragme" class="draggablewithjs" draggable="true" ondragstart="drag(event)">
</div>
<div id="dragme2" class="draggablewithangular" drag-item>
</div>
</div>
<div class="dragdrop-panel" id="drop-to-div" drop-area>
<h1>Selected</h1>
</div>
<div class="dragdrop-panel" id="trash-div" drop-area>
<h1>Trash</h1>
</div>
</div>
</body>
Javascript
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
app.directive("dropArea", function() {
return {
link: function(scope,elem, attrs) {
elem.bind('drop', function(ev){
ev.preventDefault();
var data;
if (ev.dataTransfer) {
data = ev.dataTransfer.getData('text');
}
else if (ev.originalEvent.dataTransfer){
data = ev.originalEvent.dataTransfer.getData('text');
}
//var dropObj = document.getElementById(data).cloneNode();
//dropObj.id = dropObj.id + "1";
//dropObj.setAttribute('style', 'width:50px;height:50px;background:blue;');
ev.target.appendChild(document.getElementById(data).cloneNode());
});
elem.bind('dragover', function(ev){
ev.preventDefault();
if (ev.target.getAttribute("draggable") == "true"){
ev.originalEvent.dataTransfer.dropEffect = "none";
}
else{
ev.originalEvent.dataTransfer.dropEffect = "all";
}
});
elem.css({
color: "blue"
});
}
}
});
app.directive('dragItem', function() {
return {
restrict: 'A',
replace: 'false',
link: function(scope,elem,attrs){
elem.bind('dragstart', function(ev){
if (ev.dataTransfer) {
ev.dataTransfer.setData("text", ev.target.id);
}
else if (ev.originalEvent.dataTransfer){
ev.originalEvent.dataTransfer.setData("text", ev.target.id);
}
});
elem.bind('dragover', function(ev){
return true;
});
attrs.$set('draggable','true');
}
//draggable="true" ondragstart="drag(event)"
}
});
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data).cloneNode(true));
}
and CSS
.dragdrop-panel {
width:25vw;
margin-right: 5vw;
height: 100vh;
border: 3px solid red;
float: left;
}
.draggablewithjs {
width:50px;
height:50px;
background:blue;
}
.draggablewithangular {
width:50px;
height:50px;
background:red;
}
I need to display an alert when we select same option from select(i.e presently if we have abc and again we select same option abc). How to show an alert if we select same option can any one help me using angular?
$scope.myChangeFunction = function(newValue) {
if ($scope.mySelectedOption === 'abc') {
alert("myChangeFunction if");
return
} else {
alert("myChangeFunction else");
return
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<select ng-change="myChangeFunction(mySelectedOption)" ng-model="mySelectedOption">
<option>abc</option>
<option>raj</option>
<option>jai</option>
<option>abcd</option>
</select>
You can use ngMouseup together with ngKeypress to capture user interactions with your select. One thing to mention is that mouseup will fire both when select was opened and when it was closed, so we need to track this using data(). Hope this idea will help you:
angular.module('plunker', [])
.controller('MainCtrl', function($scope) {
$scope.mySelectedOption = $scope.prevSelected = 'raj'; //initialize selected option
$scope.trackSelect = function(option, $event){
var target = angular.element($event.target);
var isOpened = target.data("isOpened");
if(isOpened) {
if (option !== $scope.prevSelected) {
$scope.prevSelected = option; //if not the same - update previous selected
} else {
alert('Value is the same!'); //if the same then show alert
}
}
target.data("isOpened", !isOpened);
};
$scope.trackKeyUp = function(option, $event) {
if ($event.keyCode === 13) {
$scope.trackSelect(option, $event);
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.angularjs.org/1.6.2/angular.js" ></script>
<html ng-app="plunker">
<body ng-controller="MainCtrl">
<select
ng-keypress="trackKeyUp(mySelectedOption, $event)"
ng-mouseup="trackSelect(mySelectedOption, $event)"
ng-model="mySelectedOption"
ng-options="o for o in ['abc', 'raj', 'jai', 'abcd'] track by o">
</select>
</body>
</html>
You can use $watch for this purpose.
$scope.$watch($scope.mySelectedOption,function(newValue,oldValue){
if(newValue == oldValue)
alert("same value selected")
})
You could create a custom dropdown in angularjs that looks like select option and use it to detect if value has changed.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.mySelectedOption = 'abc';
$scope.myChangeFunction = function(old, val) {
console.log('val', old, val)
}
$scope.options = ['jai', 'raj', 'abc'];
$scope.showdrop = false;
$scope.toogelDrop = function() {
$scope.showdrop = !$scope.showdrop;
}
$scope.selected = $scope.options[0];
$scope.selectDrop = function(index) {
if ($scope.selected === $scope.options[index]) {
console.log('same selection')
}
$scope.selected = $scope.options[index];
}
});
/* Put your css in here */
.dropdown {
border: 1px solid;
width: 50px;
cursor: pointer;
}
.dropdown div:hover {
background: #f2f2f2;
cursor: pointer;
}
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div class="dropdown" ng-click="toogelDrop()">
<div ng-if="!showdrop">{{selected}}</div>
<div ng-if="showdrop" ng-repeat="option in options track by $index">
<div ng-click="selectDrop($index)">{{option}}</div></div>
</div>
</body>
</html>
Take this HTML for example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script>
var trace = console.log.bind(console);
var vm, $$$ = {};
$(document).ready(function() {
vm = new Vue({
el: '#app',
data: {
allInfos: '',
allErrors: ''
}
});
initElements();
popupInfo('Testing box-info...');
setTimeout(function() {
popupError('Testing box-error...');
}, 3000)
});
function initElements() {
$$$.boxInfo = $('.box-info');
$$$.boxError = $('.box-error');
TweenMax.set('.box', {alpha: 0});
}
function popupInfo(msg) {
vm.allInfos = msg;
popupBox($$$.boxInfo);
}
function popupError(msg) {
vm.allErrors = msg;
popupBox($$$.boxError);
}
function popupBox(box) {
TweenMax.fromTo(
box,
0.5,
{alpha:0},
{alpha:1, onComplete: function() {
setTimeout(hideInfo.bind(box), 1000);
}}
);
}
function hideInfo() {
TweenMax.to(this, 0.5, {alpha: 0});
}
</script>
<style>
.box-info { background: #88f; }
.box-error { background: #d44; }
.box {
display: inline-block;
position: fixed;
z-index: 9999;
color: #fff;
padding: 10px;
border-radius: 10px;
}
#header {
position: relative;
top: 50px;
}
</style>
</head>
<body>
<div id="app">
<div class="box box-info" v-html="allInfos"></div>
<div class="box box-error" v-html="allErrors"></div>
<div id="header">
<h3>Testing VueJS instantiation + element references issue.</h3>
</div>
</div>
</body>
</html>
If I move the order of initElements() so that it happens BEFORE the VueJS instance is created, like this...
$(document).ready(function() {
initElements(); // <----- Moved this line
vm = new Vue({
el: '#app',
data: {
allInfos: '',
allErrors: ''
}
});
popupInfo('Testing box-info...');
setTimeout(function() {
popupError('Testing box-error...');
}, 3000)
});
...it breaks the references to the boxes HTML elements (the calls to TweenMax are operating on the detached boxes from the DOM hierarchy).
Why does this happen? And is there a way to preserve the existing elements in the #app DIV container?
I'm trying to click a button on an iPhone screen. It works fine on my computer. On the iPhone, the button highlights like the safari browser is trying to select it.
<html>
<head>
</head>
<link rel="stylesheet" href="style.css">
<body id="body" overflow="hidden" bgcolor="black" text="white">
<center>
<div class="content">
<div class="buttons">
<div class="button button1" id="button1"></div>
<div class="button button2" id="button2"></div>
</div>
</center>
</body>
<script src="engine-portal.js"></script>
<script src="socket.io.js"></script>
<script src="controller.js"></script>
<script src="controller-link.js"></script>
</html>
<style type='text/css'>
canvas {
/*border: 1px solid #aaa;*/
cursor: none;
}
</style>
<script>
</script>
'use strict';
class Controller extends Portal {
setup() {
}
connectToServer() {
this.io = io();
this.io.portal = this;
console.log("test");
this.io.emit('join', {});
}
installCanvas() {
}
installInput() {
var b1 = document.getElementById('button1');
b1.addEventListener("mousedown", this.b1down);
b1.addEventListener("mouseup", this.b1up);
b1.controller = this;
var b2 = document.getElementById('button2');
b2.addEventListener("mousedown", this.b2down);
b2.addEventListener("mouseup", this.b2up);
b2.controller = this;
}
b1down(event) {
var target = event.srcElement || event.currentTarget || event.target;
target.controller.b1Press();
}
b2down(event) {
var target = event.srcElement || event.currentTarget || event.target;
target.controller.b2Press();
}
b1up(event) {
var target = event.srcElement || event.currentTarget || event.target;
target.controller.b1Release();
}
b2up(event) {
var target = event.srcElement || event.currentTarget || event.target;
target.controller.b2Release();
}
b1Press() {
this.moveInput = -1;
}
b2Press() {
this.moveInput = 1;
}
b1Release() {
this.moveInput = 0;
}
b2Release() {
this.moveInput = 0;
}
parseInput(key_pressed_map, key_up_map, key_pressing_map, key_depressing_map) {
if (this.moveInput == 1) {
this.io.emit('input', 'down');
} else if (this.moveInput == -1) {
this.io.emit('input', 'up');
}
}
}