I have a problem trying to make a column clickable on sencha. I tried various ways, putting the text in a container, component, etc and I cant get it to react to a click.
Here is the code snippet. Check out the listener, it doesnt work when I tap on the text or that layout bar. Please help!
app.views.test = Ext.extend(Ext.Panel, {
scroll: "vertical",
id: 'test',
initComponent: function() {
var testbar = {
layout : {
type : 'vbox',
align : 'start',
pack : 'start'
},
width : '60%',
items : [{
html : 'press this column
bar : '5 0 0 15',
width : '100%'
}],
listeners: {
itemtap : function () {
console.log("goto next");
}
}
};
var testViews = {
items : [ testbar ]
};
this.items = [ testViews ];
app.views.test.superclass.initComponent.apply(this, arguments);
},
onSelect: function(sel, records){
if (records[0] !== undefined) {
}
}
});
As to answer your last comment, no, vbox might be overkill if you do not need most panel's functionalities. I would suggest to just use pure dom. The good thing about pure dom is that it you have your full control over what you need. If you use vbox, you will end up negating or disabling some of the css/functionalities it is providing.
So first, this is pure dom method: link to example
//Create a simple namespace. Habit :)
Ext.ns('NS');
/**
* This is the customized menu component
* Usage: bla bla..
*/
NS.Menu1 = Ext.extend(Ext.Component, {
/**
* #cfg menu
* An array of menu items to be rendered into the component
*/
menu: [],
initComponent: function() {
NS.Menu1.superclass.initComponent.call(this);
//We create our own customized event, so users can hook events onto it
this.addEvents({
/**
* #event menuclick
* Fires when the menu is clicked
* #param {NS.Menu1} cp this component
* #param {Menu} m The menu item
* #param {Ext.Element} a The anchor element
* ... or whatever you want to pass
*/
menuclick: true
});
//We hook an afterrender event here, so we could know
//when will be our el be rendered.
this.on('afterrender', this.onAfterRender, this);
},
onAfterRender: function() {
var me = this;
//Let's do all the fancy stuff here:
Ext.each(me.menu, function(m) {
//el property is always there as long as you subclass
//Ext.Component. It's the outermost div of the component.
//We create multiple single anchors here (of course ul/li/a is better)
var a = me.el.createChild({
tag: 'a', //so we can have :hover supports from crappy IE
html: m.text, //or anything you like
cls: 'item' //and the class to style it
//then we hook 'click' even to this anchor
}).on('click', function() {
//Then do whatever you like here
Ext.get('output1').update(m.text);
//Or even firing your own customized events, whatever you like
me.fireEvent('menuclick', me, m, a);
//or whatsoever...
});
});
}
});
//Finally, testing it out!
new NS.Menu1({
renderTo: 'menu1',
menu: [{
text: 'This is the first menu'
},{
text: 'This is the 2nd menu'
},{
text: 'This is the last menu'
}]
}).on('menuclick', function(cp, m) {
Ext.get('output2').update(m.text);
});
And then, this is the vbox way. Notice how I create them in a single loop: go to example
/**
* This is the column bars with clickable areas
*/
Ext.ns('NS');
NS.Menu2 = Ext.extend(Ext.Panel, {
/**
* #cfg menu
* An array of menu items to be rendered into the component
*/
menu: [],
border: false,
layout: {
type: 'vbox',
align: 'stretch'
},
initComponent: function() {
var me = this;
//Same thing, you can do event hook here:
me.addEvents('menuclick');
me.items = [];
//Create all the boxes as you like
Ext.each(me.menu, function(m) {
me.items.push({
html: m.text,
bodyCssClass: 'item',
bodyStyle: 'padding-bottom: 0px;margin-bottom: 0px;',
listeners: {
afterrender: function(p) {
//As you can see, we hook the afterrender event so
//when your panels (each individual panels) are created,
//we hook the click event of the panel's root el.
p.el.on('click', function() {
Ext.get('output1').update(m.text);
//Fires event
me.fireEvent('menuclick', me, m, p.el);
});
}
}
});
});
NS.Menu2.superclass.initComponent.call(this);
}
});
new NS.Menu2({
renderTo: 'menu2',
height: 300,
menu: [{
text: 'This is the first menu'
},{
text: 'This is the 2nd menu'
},{
text: 'This is the last menu'
}]
}).on('menuclick', function(cp, m) {
Ext.get('output2').update(m.text);
});
Both of them looks similar, just vbox way is a little bit overkilling as it processed a little bit more stuff than using pure dom. Inspect both generated dom nodes to see the differences.
This is the dom nodes generated in example 1:
<div id="ext-comp-1001">
<a class="item" id="ext-gen3">This is the first menu</a>
<a class="item" id="ext-gen4">This is the 2nd menu</a>
<a class="item" id="ext-gen5">This is the last menu</a>
</div>
And this is in example 2:
<div id="ext-comp-1001" class=" x-panel x-panel-noborder">
<div class="x-panel-bwrap" id="ext-gen3">
<div class="x-panel-body x-panel-body-noheader x-panel-body-noborder x-box-layout-ct" id="ext-gen4" style="height: 300px; ">
<div class="x-box-inner" id="ext-gen6" style="width: 836px; height: 300px; ">
<div id="ext-comp-1002" class=" x-panel x-box-item" style="width: 836px; left: 0px; top: 0px; ">
<div class="x-panel-bwrap" id="ext-gen7"><div class="x-panel-body item x-panel-body-noheader" id="ext-gen8" style="padding-bottom: 0px; margin-bottom: 0px; width: 824px; height: 24px; ">This is the first menu</div>
</div>
</div>
<div id="ext-comp-1003" class=" x-panel x-box-item" style="width: 836px; left: 0px; top: 31px; ">
<div class="x-panel-bwrap" id="ext-gen10">
<div class="x-panel-body item x-panel-body-noheader" id="ext-gen11" style="padding-bottom: 0px; margin-bottom: 0px; width: 824px; height: 24px; ">This is the 2nd menu</div>
</div>
</div>
<div id="ext-comp-1004" class=" x-panel x-box-item" style="width: 836px; left: 0px; top: 62px; ">
<div class="x-panel-bwrap" id="ext-gen13">
<div class="x-panel-body item x-panel-body-noheader" id="ext-gen14" style="padding-bottom: 0px; margin-bottom: 0px; width: 824px; height: 24px; ">This is the last menu</div>
</div>
</div>
</div>
</div>
</div>
Get what I mean?
Related
I'm creating dynamic tabs. I'm currently facing two problems:
When I click on the span x to delete current tab, it deletes all my tabs.
When I getting the array data, it always gets the first tab data only.
Can anyone help me with this? I've tried many ways but I still cannot get my desired result. Here is my fiddle Dynamic Tabs.
Currently my array result looks like this for the 2nd problem when there is two tabs, '2023' and '2025':
[{
February: "1",
January: "1",
Year: "2023"
}, {
February: "1",
January: "1",
Year: "2023"
}]
My expected result would be:
[{
February: "1",
January: "1",
Year: "2023"
}, {
February: "1",
January: "1",
Year: "2025"
}]
$(document).ready(function() {
addTab();
});
$('#add_tab').click(function() {
addTab()
});
//delete current tab
$(".nav-tabs").on("click", "span", function() {
var anchor = $(this).siblings('a');
console.log(anchor)
$(anchor.attr('href')).remove();
$(this).parent().remove();
$(".nav-tabs").children('a').first().click();
});
function addTab() {
var nextTab = $(".nav-tabs").children().length;
var date = new Date().getFullYear() + nextTab;
// create the tab
$('<a class="nav-link" href="#tab-' + date + '" data-toggle="tab">' + date + '</a><span> x </span>').appendTo('#tabs');
// create the tab content
var html = "";
html += '<div class="tab-pane monthSettings" id="tab-' + date + '">';
html += '<label><b>Year: </b></label>';
html += '<input class="txtYear" type="text" value="' + date + '">';
html += '<label><b>January: </b></label>';
html += '<input class="txtJanuary" type="number" value="1">';
html += '<label><b>February: </b></label>';
html += '<input class="txtFebruary" type="number" value="1">';
html += '</div>';
//append to tab-content
var test = $(html).appendTo('.tab-content');
// make the new tab active
$('#tabs a:last').tab('show');
}
//get array
$(document).on('click', '#btnGetArray', function(e) {
var array = []
$(".monthSettings").each(function() {
let detail = {
Year: $(".txtYear").val() || 0,
January: $(".txtJanuary").val() || 0,
February: $(".txtFebruary").val() || 0,
}
array.push(detail)
console.log(array)
});
});
#import url('http://getbootstrap.com/2.3.2/assets/css/bootstrap.css');
.container {
margin-top: 10px;
}
.nav-tabs>a {
display: inline-block;
position: relative;
margin-right: 10px;
}
.nav-tabs>a>span {
display: none;
cursor: pointer;
position: absolute;
right: 6px;
top: 8px;
color: red;
}
.nav-tabs>a>span {
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="https://getbootstrap.com/2.3.2/assets/js/bootstrap.js"></script>
<link rel="stylesheet" type="text/css" href="https://getbootstrap.com/2.3.2/assets/css/bootstrap.css">
<div class="bg-gray-300 nav-bg">
<nav class="nav nav-tabs" id="tabs">
+ Add Year
</nav>
</div>
<div class="card-body tab-content"></div>
<button id="btnGetArray">GetData</button>
The issue is because your selectors for retrieving the .txtYear, .txtJanuary and .txtFebruary will only look at the value of the first element in the collection, no matter how many it finds.
To correct this you can use find() from the parent element, which you can reference from the each() loop, to retrieve the child elements in that iteration.
Taking this a step further, you can simplify the logic by using map() instead of each() to build your array, but the use of find() remains the same.
In addition, there's some other improvements which can be made to the code, such as ensuring all event handlers are within document.ready and using template literals to make the HTML string concatenation easier to read.
jQuery($ => {
$('#add_tab').on('click', addTab);
addTab();
$(".nav-tabs").on("click", "span", function() {
var anchor = $(this).siblings('a');
console.log(anchor)
$(anchor.attr('href')).remove();
$(this).parent().remove();
$(".nav-tabs").children('a').first().click();
});
$(document).on('click', '#btnGetArray', e => {
var array = $(".monthSettings").map((i, container) => ({
Year: $(container).find('.txtYear').val() || 0,
January: $(container).find('.txtJanuary').val() || 0,
February: $(container).find('.txtFebruary').val() || 0,
})).get();
console.log(array);
});
});
function addTab() {
var nextTab = $(".nav-tabs").children().length;
var date = new Date().getFullYear() + nextTab;
$(`<a class="nav-link" href="#tab-${date}" data-toggle="tab">${date}</a><span> x </span>`).appendTo('#tabs');
var html = `
<div class="tab-pane monthSettings" id="tab-${date}">
<label><b>Year: </b></label>
<input class="txtYear" type="text" value="${date}" />
<label><b>January: </b></label>
<input class="txtJanuary" type="number" value="1" />
<label><b>February: </b></label>
<input class="txtFebruary" type="number" value="1" />
</div>`
var test = $(html).appendTo('.tab-content');
// make the new tab active
$('#tabs a:last').tab('show');
}
#import url('http://getbootstrap.com/2.3.2/assets/css/bootstrap.css');
.container {
margin-top: 10px;
}
.nav-tabs>a {
display: inline-block;
position: relative;
margin-right: 10px;
}
.nav-tabs>a>span {
display: none;
cursor: pointer;
position: absolute;
right: 6px;
top: 8px;
color: red;
}
.nav-tabs>a>span {
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript" src="https://getbootstrap.com/2.3.2/assets/js/bootstrap.js"></script>
<link rel="stylesheet" type="text/css" href="https://getbootstrap.com/2.3.2/assets/css/bootstrap.css">
<div class="bg-gray-300 nav-bg">
<nav class="nav nav-tabs" id="tabs">
+ Add Year
</nav>
</div>
<div class="card-body tab-content"></div>
<button id="btnGetArray">GetData</button>
I am using angularjs and having a simple accordion with expand and collapse,Every thing is working fine but here when I expand the div it should expand slowly and similarly when I collapse again it should collapse slowly.Here I am using isopen for expand in angularjs.Anyone can help me,Below is my code,https://plnkr.co/edit/nCdGzZYPSTYsMPYf8K9o?p=preview
HTML
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-sanitize.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.js'></script>
<script src="js/index.js"></script>
<link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css'>
<body ng-app="app">
<h1>Dynamic accordion: nested lists with html markup</h1>
<div ng-controller="AccordionDemoCtrl">
<div>
<div ng-repeat="group in groups track by $index">
<div class="parents" ng-click="open($index)"><i ng-class="{'glyphicon-minus': group.isOpen, 'glyphicon-plus': !group.isOpen}"></i> {{ group.title }}
</div>
<div class="childs" ng-show="group.isOpen">ddddd</div>
</div>
</div>
</div>
</body>
index.js
var app=angular.module('app', ['ui.bootstrap','ngSanitize','angular.filter']);
app.controller('AccordionDemoCtrl', function ($scope) {
$scope.oneAtATime = true;
$scope.open = function (index) {
$scope.groups[index].isOpen = !$scope.groups[index].isOpen;
$scope.closeOthers(index);
}
$scope.closeOthers = function (index) {
for(var i = 0; i < $scope.groups.length; i++) {
if (i !== index)
$scope.groups[i].isOpen = false;
}
}
$scope.groups = [
{
title: 'title 1',
list: ['<i>item1a</i> blah blah',
'item2a',
'item3a']
},
{
title: 'title 2',
list: ['item1b',
'<b>item2b </b> blah ',
'item3b']
},
{
title: 'title 3',
},
{
title: 'title 4',
},
{
title: 'title 5',
}
];
$scope.groups[0].isOpen = true;
});
You can use css max-height and add transition to make collapse and expand slowly
.childs {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-out;
}
.childs.showChild {
max-height: 1000px;
}
<ul class="childs" ng-class="{'showChild': group.isOpen}">
<li ng-repeat="item in group.list">
<span ng-bind-html="item"></span>
</li>
</ul>
See the demo
https://plnkr.co/edit/Gm7oe8l3ZBXyWTe3Okm4?p=preview
I have created an OverlayPanel like component so there I can put more clicks or something else.
But when I click outside the overlay or in the overlay this does not exit stays always there, it is dissapear only when I click in button what I have writed.
Here is the link of the StackBlitz
I have like this the overlaPanel created.
<div class="dropdown">
<div (click)="toggle()" class="body">
<ng-content select="[body]"></ng-content>
</div>
<div *ngIf="active" class="popup" >
<ng-content select="[popup]"></ng-content>
</div>
</div>
.dropdown {
position: relative;
display: inline-block;
}
.popup {
display: block;
position: absolute;
z-index: 1000;
}
export class OverlaypanelComponent implements OnInit {
active = false;
constructor() {
}
offClickHandler(event: any) {
if (event['.body'] && event['.popup'] === true) {
this.active = false;
}
}
ngOnInit(): void {
}
toggle() {
this.active = !this.active;
}
close() {
this.active = !this.active;
}
}
And this is when I call this component
<app-overlaypanel>
<div body [ngClass]="[getBackgroundColorClass(),clazz]" class="fa fa-pencil-square-o edit-block"></div>
<div class="overlayPopup" popup>
<div class="dropdown-menu-item" (click)="openTechnicalEditDialog({cluster: cluster, type: clazz})">Edit</div>
<div class="dropdown-menu-item" (click)="delete()">Delete</div>
<div class="dropdown-menu-item" (click)="openTechnicalEditDialog({appendToParentId: cluster.id})" *ngIf="cluster.level <= 9">Append</div>
<div
class="dropdown-menu-item" (click)="clicked.emit()">Assign</div>
</div>
</app-overlaypanel>
If you want to close the drop down when you click outside of your menu you can use host listener to know whether you clicked outside or not
#HostListener('document:click', ['$event']) clickedOutside($event){
this.active=false;
}
I have attached the example check this out: https://stackblitz.com/edit/angular-5p5d1b
You can use ng-click-outside module as described here https://www.npmjs.com/package/ng-click-outside
working with me fine in angular 8
I know the question says Angular 4 but incase if someone is wondering how can we do the same with latest version of angular.
Now Anglar Material overlay comes with such directive and event listener.
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="trigger"
[cdkConnectedOverlayOpen]="isOpen"
[cdkConnectedOverlayHasBackdrop]="isOpen"
[cdkConnectedOverlayBackdropClass]="'cdk-overlay-transparent-backdrop-cs'"
(backdropClick)="isOpen = !isOpen"
>
content to be shown on overlay
</ng-template>
I am able to display file image and title on mouseovering for respective file. But for all filename the image and title is displaying in same place.
I need to display the respective image and title on above of respective filename. When page gets loaded I saw this small box. I don't know why.
After moving mouseover on first filename or second filename it will display the image and title in the same place as below.
HTML :
<style>
.hover-image {
width: 30px;
height: 30px;
border-radius: 20%;
position: absolute;
margin-top: -10px;
margin-left: 5px;
}
img.hover-image {
border: none;
box-shadow: none;
}
.hover-title {
color:black;
position: absolute;
margin-top: -20px;
}
</style>
<div class="file-image-tags1">
<ul>
<span style="width: 200px;"><a ng-show="hideHoveredImage==false;" class="hover-title">{{hoverTitle}}<img class="hover-image" src="{{hoveredImage}}"></a></span>
<li ng-repeat="image in files | filter :'image'" >
<div class="file-tag-baloon1" ng-mouseover="hoverImg(image.id)" ng-mouseleave="hoverOut()">
<span>
<a ng-click="photoPreview(image.id);" >{{image.fileshortname}}</a>
</span>
<span><a ng-click="removeImage(image.id)" class="remove1">X</a></span>
</div>
</li>
</ul>
</div>
Use the angular built in directives,
Check out the below code
HTML
<span ng-hide="show">
<img ng-src="https://unsplash.it/200/300/?random" />
</span>
<br/>
<span ng-mouseover="show=!show" ng-mouseleave="show=!show">
Image name </span>
Angular Controller
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.show="false";
});
Update 1:
Based on the comment I updated as below
Angular Controller
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.show = "false";
$scope.arrayofJson = [{
imageTitle: "someImageName1",
imagePath: "http://lorempixel.com/400/200/",
show: "false"
}, {
imageTitle: "someImageName2",
imagePath: "https://unsplash.it/200/300/?random",
show: "false"
}, {
imageTitle: "someImageName3",
imagePath: "https://unsplash.it/200/300/?random",
show: "false"
}, {
imageTitle: "someImageName4",
imagePath: "https://unsplash.it/200/300/?random",
show: "false"
}
];
});
HTML
<div ng-repeat="item in arrayofJson">
<span ng-hide="item.show">
<img ng-src="{{item.imagePath}}" /> </span>
<br/>
<span ng-mouseover="item.show=!item.show" ng-mouseleave="item.show=!item.show">
{{item.imageTitle}} </span>
</div>
The plunker remains the same and it is updated. Check out the LIVE DEMO
Try -
.file-image-tags1
{
position : absolute;
}
You can do this using ng-if ng-show/hide like below example.
$scope.hoverIn = function(){
this.hoverImage = true;
};
$scope.hoverOut = function(){
this.hoverImage = false;
};
<ul>
<span ng-mouseover="hoverIn()" ng-mouseleave="hoverOut()">Hover Me</span>
<span ng-show="hoverImage">
<img>.....</a>
</span>
</li>
</ul>
in function you can pass the file name and you can do much more
i am using the .animate function to animate a div inside another div.
it works fine, in the first block of divs in the same page, but it doesnt in the other divs.
any ideas on how to fix that?
here is the jsfiddle example http://jsfiddle.net/atseros/CkaHG/2/
$(document).ready(function() {
$("#displayscroll").hover(
//on mouseover
function() {
$(this).animate({
height: '+=170'
}, 'slow'
);
},
//on mouseout
function() {
$(this).animate({
height: '-=170px'
}, 'slow'
);
}
);
});
change id to other attribute.
change id to class sample:
html:
<div id="displaybox">
<div id="displayboximg">
<div class="displayscroll"> <!-- id to class -->
<div style="margin-top:50px; margin-left:20px; font-weight:bolder;"></div>
</div>
</div>
<div id="displayboxdetails">
details
</div>
</div>
<div id="displaybox">
<div id="displayboximg">
<div class="displayscroll"> <!-- id to class -->
<div style="margin-top:50px; margin-left:20px; font-weight:bolder;"></div>
</div>
</div>
<div id="displayboxdetails">
details
</div>
</div>
script :
$("div.displayscroll").hover( // <---- change to class
//on mouseover
function() {
$(this).animate({
height: '+=170' //adds 250px
}, 'slow' //sets animation speed to slow
);
},
//on mouseout
function() {
$(this).animate({
height: '-=170px' //substracts 250px
}, 'slow'
);
}
);
css :
.displayscroll {
height:30px;
overflow:hidden;
opacity:0.82;
position:absolute;
left:0px;
right:0px;
bottom:0;
text-align:justify;
background-color:#4e81bc;
}