Dojo destroy MenuItems on DropDownButton - javascript

I have the following markup:
<button dojoType="dijit.form.DropDownButton" dojoAttachPoint="labels" label="Labels">
<div dojoType="dijit.Menu" dojoAttachPoint="labelsMenu"></div>
</button>
I am adding MenuItems programatically and it works fine for the first time. But when I want to refresh I get an error: Tried to register widget with id==16 but that id is already registered. I have tried the following code to clear but it's not working:
var labels = dijit.findWidgets(this.labels);
dojo.forEach(labels, function (l) {
l.destroyRecursive();
});
dojo.empty(dojo.byId(this.labels));
I have also try the same thing for labelsMenu to empty it but no luck. Is there any other way to get rid of all children when reloading data or am missing something?

I have solved it and here's what I did:
var menuChildren = dijit.byId(this.labelsMenu).getChildren();
if (menuChildren.length > 0){
dojo.forEach(menuChildren, function(mc){
mc.destroyRecursive();
});
}

In your code you call dojo.empty on the labels. dojo.empty() empties the element in the DOM but keeps the original element. So try calling dojo.empty on the dijit menu instead.
dojo.empty(dojo.byId("labelsMenu"));
For reference, in a fully baseless application, the dom-construct module is used.
require(["dojo/dom-construct"], function(domConstruct){
// Empty node's children byId:
domConstruct.empty("someId");
});

Related

How to specify a child component to drag its parent component in React?

I'm currently working on a terminal emulator project using React and styled-components. I want to add dragging feature to the terminal. Everything is good, except one thing: I want to click and hold the title bar to drag the terminal, not somewhere else.
Here is my base component: https://codesandbox.io/s/still-http-jxxex
I don't want to use any plugins or libraries because I want to know how it works. So are there any ways to achieve this just by React and javascript? Every comments are appreciated to me.
Well, after reading MDN docs
here is a very simplified version of d&d(the rest is up to you so please read the docs):
link to codesanbox
Bellow is the MDN example my answer based on:
<script>
function dragstart_handler(ev) {
// Add the target element's id to the data transfer object
ev.dataTransfer.setData("application/my-app", ev.target.id);
ev.dataTransfer.dropEffect = "move";
}
function dragover_handler(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move"
}
function drop_handler(ev) {
ev.preventDefault();
// Get the id of the target and add the moved element to the target's DOM
const data = ev.dataTransfer.getData("application/my-app");
ev.target.appendChild(document.getElementById(data));
}
</script>
<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">This element is draggable.</p>
<div id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Zone</div>
After days of searching, I found out the problem is that I triggered onMouseDown in window (globally).
In order to do this, I use a function that passed to the child component to update its parent component's states, which is onMouseDown, then got rid of the function in useEffect.
Here's my final solution: https://codesandbox.io/s/admiring-liskov-puu6g

google maps select infowindow DOM element from angularjs directive

I need to select the element by class 'gm-style-iw' to fix some styles in Infowindow. The selection is happening inside of the angularjs directive.
<div ui-view="full-map" id="full-map" class="mainMap col-xs-6"></div>
ui-view - loading a directive with IW content. map is initialized inside that directive.
on the directive's controller initialization i have to edit element with class 'gm-style-iw'.
var iwElem = $document[0].getElementsByClassName("gm-style-iw")
does return the correct element.
console.log(iwElem) result is:
[]
length: 1
0: div.gm-style-iw
__proto__: HTMLCollection
However i'm stuck after it.
it as an HTMLCollection, which is the array of HTML elements, as i understand. => i must be able to get this 0 element by iwElem[0], the strange thing is that iwElem[0] returns undefined.
Also tried with jquery selectors:
$('.gm-style-iw') => length:0
$('div.gm-style-iw') => length:0
If you are sure that your html is something like
<div ui-view="full-map" id="full-map" class="mainMap col-xs-6">
...some codes
<div class="gm-style-iw"></div>
... other codes
</div>
And if your are using JQuery, how about trying the following selector?
$('.mainMap .gm-style-iw')
which means getting the child node of class .gm-style-iw under the parent node of class .mainMap
The problem is partially solved.
$timeout(function() {
removeIwStandardStyles()
},300);
function removeIwStandardStyles () {
var iwOuter = $(iwOuterTemp);
while (iwOuterTemp.length < 1){
iwOuterTemp = document.getElementsByClassName("gm-style-iw");
}
var iwBackground = iwOuter.prev();
iwBackground.children(':nth-child(2)').css({'display' : 'none'});
iwBackground.children(':nth-child(4)').css({'display' : 'none'});
}
$document[0].getElementsByClassName("gm-style-iw") was catching a corrent elements, but seems like they was not applied to DOM yet, or some other load issues.
However, the solution is not complete (see a while) - i suppose i can do that cause that element is definitely going to load. $timeout itself isn't helping completely - sometimes it does wait till complete IW load, sometimes not.

How to get an element with condition of modal dialog in Angular 2?

I'm using ng2-modal to create a modal dialog in Angular 2. I am unable to get an element that has a condition on it (#myModalScrollPanel).
Template (modal.html):
<modal #myModal title="{{title}}"
cancelButtonLabel="Close"
submitButtonLabel="Ok"
modalClass="#modal-md"
[hideCloseButton]="false"
[closeOnEscape]="false"
[closeOnOutsideClick]="false"
>
<modal-header></modal-header>
<modal-content>
<div class="row">
<div *ngIf="logOutput" class="col-md-12">
<div id="myModalScrollPanel" #myModalScrollPanel class="panel-body fixed-panel">
<p *ngFor="let entry of logOutput.entries">{{entry.log}}</p>
</div>
</div>
</div>
</modal-content>
<modal-footer></modal-footer>
</modal>
In my component I get View Children (modal.component.ts):
#ViewChild('myModal') myModalModal;
#ViewChild('myModalScrollPanel') myModalScrollPanel;
After a users clicks a button, I show the modal and get log text from the server, I call updateScrollPosition() once I have updated logOutput (modal.component.ts):
updateScrollPosition() {
console.log("modal:");
console.log(this.myModalModal);
console.log("log scroll panel:");
console.log(this.myModalScrollPanel);
if(this.myModalScrollPanel){
console.log("Scrolling the panel down");
this.myModalScrollPanel.nativeElement.scrollTop = this.myModalScrollPanel.nativeElement.scrollHeight;
} else {
console.log("No log scroll panel.");
}
}
The console shows a valid object for "modal" and 'undefined' for log scroll panel.
I also tried calling that method from ngAfterViewInit(), but it only gets called when the parent component is loaded, and not the actual modal being shown, so the if statement results in false and element doesn't exist yet. If I remove/move the if statement, so that the element exists I can then access that object, but the changes I make do not take any effect, although that might be a whole different issue (most likely to do with change detection).
In the end, I just want to scroll to the bottom of the panel. Something like this (which works in the browser console):
var scrollPanel = document.getElementById('myModalScrollPanel');
scrollPanel.scrollTop = scrollPanel.scrollHeight;
Thanks in advance!
So to answer my own question, I had to use #ViewChildren instead of #ViewChild.
#ViewChildren annotation will assign a QueryList object to your variable, giving you access to the elements you require (I use .toArray() to get an array of elements, which in this case will be just one).
Speaking of the change detection problem I had, thanks to this answer, using the ngAfterViewChecked() method I was able to implement the scroll down I needed.

Polymer - Get data-bound attribute value in repeating template

I'm having a bit of an issue here. I had a small amount of success with event.target.templateInstance.model.thing syntax to get the value of attributes from within a repeating template but I keep getting back undefined from this bit of code I have here:
downloadFunction: function (e) {
console.log("dl function clicked");
//get particular id of thing
var fu = e.target.templateInstance.model.s.soundId;
console.log(fu);
//^ returns "TypeError: Cannot read property 'soundId' of undefined"
}
And my repeating template is here:
<div layout horizontal wrap center center-justified>
<template repeat="{{s in carddata}}">
<sound-card image="{{s.imgurl}}"
quotetext="{{s.quote}}"
soundsrc="{{s.soundurl}}"
soundref="{{s.soundId}}"
downloadfunction="{{downloadFunction}}">
</sound-card>
</template>
</div>
Where carddata is just an array with my data in it. All of the values are generated fine so I know it's not an issue with my array. I'm just confused how exactly I'm supposed to target someting from within the repeating template? Am I calling it at the wrong time? Or am I messing up the syntax of the templateInstance bit?
If it matters, I'm trying to get it to work in an Android 4.4 webView using Apache Cordova. 4.4 webView doesn't appear to enjoy the shadowDOM terribly much.
Thanks!
edit: After some jiggery pokery with console logs, it appears that the sender value is referring to the div that I apply the on-click="{{downloadFunction}} to. Here's the template that I am repeating, if this provides any insight.
<div class="soundcard-container" vertical layout>
//can't target this one either on WebView 4.4, works on ChromeOS
<img src="{{image}}" on-tap="{{playAudio}}">
<div class="soundcard-bottom-container" horizontal layout center justified>
<span>{{quotetext}}</span>
//I have an 'a' tag for desktop browsers and the div tag is targeting my Android/iOS
//apps that I am exporting as a webView to using Apache Cordova. Webonly is hidden
//at the point where I'm trying to get my downloadfunction to work.
//console.log(sender) in my downloadfunction returns this div v
<div on-tap="{{downloadfunction}}" class="mobileonly"></div>
</div>
//just a hidden audio thing for web
<div style="display: none">
<audio id="{{soundref}}" src="{{soundsrc}}" controls preload="auto"></audio>
</div>
</div>
edit2 some console logs..
console.log(sender) and console.log(event.target) are both the same div that has the on-click event for my downloadFunction.. not sure if this should be the case.
console.log(e.target.templateInstance.model) returns my <sound-card> object, I believe like it should(?)
It's just when I add the specific .s.soundId that it's undefined. I'm not sure why it's unable to find it.. Maybe there's another way to get the specific soundId (or s.soundId rather) of that particular <sound-card> object?
I'll bet you want to refer to the "sender" of the event—not e.target. See the part about inSender at https://www.polymer-project.org/0.5/docs/polymer/polymer.html#declarative-event-mapping:
inSender: A reference to the node that declared the handler. This is
often different from inEvent.target (the lowest node that received the
event) and inEvent.currentTarget (the component processing the event),
so Polymer provides it directly.
This might fix it:
downloadFunction: function (e, detail, sender) {
console.log("dl function clicked");
//get particular id of thing
var fu = sender.templateInstance.model.s.soundId;
console.log(fu);
}
Alright I was able to fit this in a different way. I wasn't able to get e.target.templateInstance.model.s.soundId bit to work, so instead on the div that I call the event on (event.target) I gave it an attribute called data-soundid and passed it {{soundref}} from my original template and then where I repeat that template I simply made a function like so:
downloady: function (e) {
console.log(e.target.getAttribute('data-soundurl'));
}
Ta da! Very nice solution. Thanks to Eyal who suggested this to me in a previous question. It works like a charm. :-)
Here is working example of using templateInstance, with included selecting by dynamic ID: Plunk .
As for your code, can't tell why it's not working.
handleEvent: function(e, detail, sender) {
console.log('handleEvent');
console.log(sender.id);
//How to catch full_obj here,
//..as if first item is clicked: full_obj = {"firstName":"John", "lastName":"Doe"}
//console.log(e);
console.log(e.target.templateInstance.model.item.firstName);
//console.log(detail);
//console.log(sender);
this.instance_firstName = e.target.templateInstance.model.item.firstName;
this.instance_lastName = e.target.templateInstance.model.item.lastName;
//Selecting by dynamic ID
var clicked_element = this.shadowRoot.querySelector('#'+this.instance_firstName);
console.log('Selecting');
console.log(clicked_element);
//var second_element = sender.templateInstance.model.querySelector('my-second-element');
//var second_element = this.$.second_element;
}
Edit:
Event handling and data binding Docs

Counting classes on another page and displaying them

To save me a lot of work editing a number in when adding a document to a site I decided to use javascript to count the number of elements with a class doc .
I am two main problems:
There is trouble displaying the variable. I initially thought this was because I hadn't added function, however when I tried adding this the variable was still not displayed.
The elements with the class I want to count are on another page and I have no idea how to link to it. For this I have tried var x = $('URL: /*pageURL*/ .doc').length; which hasn't worked.
Essentially I want the total elements with said class name and this to be displayed in a span element.
Currently I have something similar to what's displayed below:
<script>
var Items = $('.doc').length;
document.getElementById("display").innerHTML=Items;
</script>
<span id="display"></span>
Found an example of something similar here where the total numbers of articles are displayed.
Edit:
#ian
This code will be added to the homepage, domain.net/home.html. I want to link to the page containing this documents, domain.net/documents.html. I've seen this done somewhere before and if I remember correctly they used url:domainname.com/count somewhere in their code. Hope this helps.
Here is a jQuery call to retrieve the url "./" (this page) and parse the resulting data for all elements with class "lsep" "$('.lsep', data)". You should get back a number greater than 5 or so if you run this from within your debug console of your browser.
$.get("./", function(data, textStatus, jqXHR)
{
console.log("Instances of class: " + $('.lsep', data).length)
});
One important thing to remember is that you will run into issues if the URL your are trying to call is not in the same origin.
Here's an updated snippet of code to do what you're describing:
$(document).ready(
function ()
{
//var url = "/document.html" //this is what you'd have for url
//var container = $("#display"); //this is what you'd have for container
//var className = '.data'; //this is what you'd have for className
var url = "./"; //the document you want to parse
var container = $("#question-header"); //the container to update
var className = '.lsep'; //the class to search for
$.get(url, function (data, textStatus, jqXHR) {
$(container).html($(className, data).length);
});
}
);
If you run the above code from your browser's debug console it will replace the question header text of "Counting classes on another page and displaying them" with the count of instances the class name ".lsep" is used.
First, you have to wait until the document is ready before manipulating DOM elements, unless your code is placed after the definition of the elements you manipulate, wich is not the case in your example. You can pass a function to the $ and it will run it only when the document is ready.
$(function () {
//html() allows to set the innerHTML property of an element
$('#display').html($('.doc').length);
});
Now, if your elements belongs to another document, that obviously won't work. However, if you have used window.open to open another window wich holds the document that contains the .doc elements, you could put the above script in that page, and rely on window.opener to reference the span in the parent's window.
$('#display', opener.document.body).html($('.doc').length);
Another alternative would be to use ajax to access the content of the other page. Here, data will contain the HTML of the your_other_page.html document, wich you can then manipulate like a DOM structure using jQuery.
$.get('your_other_page.html', function(data) {
$('#display').html($('.doc', data).length);
});

Categories

Resources