I am trying to implement nested drag and drop functionality in angular project. For this I am using https://www.npmjs.com/package/ng-drag-drop.
HTML:
<ul>
<li class="parent" draggable [dragScope]="'parentLayout'">Row with Tow Columns</li>
</ul>
<div droppable [dropScope]="'parentLayout'" [dragOverClass]="'drag-target-border'" (onDrop)="onLayoutDrop($event)">
<div class="layout-container">Add Element Container Here</div>
</div>
Inside the 'layout-container' I want to drag and drop another HTML code. which is:
<div class="container">
<div class="row">
<div class="col-6" droppable [dropScope]="'element'">Column A - Add Element</div>
<div class="col-6" droppable [dropScope]="'element'">Column B - Add Element</div>
</div>
</div>
As you can notice, I want to enable second droppable div inside parent div. This works perfectly when I hardcoded the code. However, I want to fetch the code from database. So I tried using innerHTML, but its not detecting the ng-drag-drop scopes (droppable, [dropScope], etc).
.ts
inner_html: string = '';
// Fetched from database
layout: any = `<div class="container">
<div class="row">
<div class="col-6" droppable [dropScope]="'element'">Column A - Add Element</div>
<div class="col-6" droppable [dropScope]="'element'">Column B - Add Element</div>
</div>
</div>`;
innerElement: string = `<h1>Final Element</h1>`; // This is fetched from database
onLayoutDrop(){
this.inner_html += this.layout;
}
.html
<ul>
<li class="parent" draggable [dragScope]="'parentLayout'">Row with Tow Columns</li>
</ul>
<div droppable [dropScope]="'parentLayout'" [dragOverClass]="'drag-target-border'" (onDrop)="onLayoutDrop($event)">
<div class="layout-container">Add Element Container Here</div>
</div>
<div class="innerhtml" [innerHTML]="layout"></div>
Hey I hope you have the possibility to change your data that is fetched from the api. I really hope you get a proper model in JSON format and do not get some rigged HTML from your backend.
Because:
The data persistence should not know how the data is presented
HTML in the Database is a security flaw
With innerHtml you are working around angulars change detection
My advice: If it feels quirky to implement, it usually is quirky to implement.
So to a solution for your very problem:
Separate Data from Layout:
export interface SomeElement {
description: string;
}
Use *ngFor
<div class="container">
<div class="row">
<div class="col-6" droppable [dropScope]="'element'" *ngFor="let element of elementsFromDb">{{ element.description }}</div>
</div>
</div>
fetch data
elementsFromDb: SomeElement = /* fetch an array that looks like this [{ description: 'Column A - Add Element' }, { description: 'Column B - Add Element'}] */
Related
Can I add div contents (innerText / textContent) after adding a div in the parent class using JavaScript. I know it's confusing and also I am not sure whether my demand is correct or not.
Can someone just help how to achieve below HTML results using JS.
<div class="container">
<div class="mesg left">
<div class="username">
You
</div>
The main content goes here
<span id="time">08:23am</span>
</div>
</div>
I had tried to achieve this but I my case the content comes up... Like(see the output html from what I have did from JS)
<div class="container">
<div class="description">
The main content goes here
<div class="name">
James
</div>
<span id="time">08:23am</span>
</div>
</div
You can use Node.insertBefore to place the text before the timestamp.
Given your HTML this would work:
const time = document.getElementById("time")
const content = document.createElement("p")
content.innerText = "The main content goes here"
document.getElemenstByClassName("mesg left")[0]
.insertBefore(content, time)
i have dynamic data in my rails view, all divs have the same name; 'allData', which has alot of info, so i have it not displayed, i want to display that specific div and not all divs when i click show, but it shows all divs, i want to be able to show just that target div i clicked
$('.show'').on('click', (event) =>{
$('.allData').toggle();
$(event.currentTarget).closest('.allData').toggle();
})
<div class='eachData'>
<div class='header'>
<div class='show'> show</div>
<div class='numberOfdata'> 100</div>
</div>
<div class='allData; display:none'>
"foobar all data is here"
</div>
</div>
<div class='eachData'>
.......
</div>
<div class='eachData'>
.......
</div>
Your closest call is on the right track but you're not quite using it right. First you want to find the container (.eachData) that contains your <div class="show">, you use closest for that:
let container = $(event.currentTarget).closest('.eachData');
then you search within that container for the .allData you want to toggle by using find:
container.find('.allData').toggle();
So you use closest to go up the node tree and then find to come back down.
BTW, this:
<div class='allData; display:none'>
should be:
<div class="allData" style="display: none">
The class attribute contains CSS class names delimited by whitespace, raw CSS goes in the style attribute and is delimited by semicolons.
Your inline style on the div should be as follows:
<div class="allData" style="display: none">
Then try the following:
$('.show').on('click', function() {
$(document).find('.eachData .allData:visible').hide('fast');
$(this).parent().closest('.allData').show('fast');
});
I want to move a DOM element inside the DOM but whilst still keeping it in its own container.
Take the following HTML:
<div class="contain">
<div class="bit">A</div>
<div class="bit">B</div>
<div class="bit">C</div>
<div class="bit">D</div>
<div class="bit">E</div>
</div>
I want to put the .bit containing A to the end of this list, just below E whilst still keeping it inside the div .contain.
I have tried the following:
$('.contain').find('bit').first().appendTo('.contain');
and:
$('.contain').find('bit').first().insertAfter($('.contain').find('bit').last());
And neither of them work.
I have very little control over the HTML. For example I can't give each .bit its own unique ID.
Can someone explain what I am doing wrong?
Just append it to the same container and A is moved to the end of the list.
Your two attempts works - you have missed the . for the find('.bit') part.
See demo below:
$('.contain').append($('.contain .bit:first-child'));
// the below works too
// $('.contain').find('.bit').first().appendTo('.contain');
// and even this works
// $('.contain').find('.bit').first().insertAfter($('.contain').find('.bit').last());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="contain">
<div class="bit">A</div>
<div class="bit">B</div>
<div class="bit">C</div>
<div class="bit">D</div>
<div class="bit">E</div>
</div>
You need to use the class selector ., which you already use for .contain
$('.contain').find('.bit').first().appendTo('.contain');
working snippet:
$('.contain').find('.bit').first().appendTo('.contain');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="contain">
<div class="bit">A</div>
<div class="bit">B</div>
<div class="bit">C</div>
<div class="bit">D</div>
<div class="bit">E</div>
</div>
Noob here sorry. I'm trying to remove an ancestor when my WP loop returns an empty message with a specific class. Firefox is displaying as intended, removing the desired DOM, but Chrome is removing the targeted element and no ancestors.
Basic HTML markup:
<div id="content" class="container site-content">
<div id="primary" class="main-content">
<div id="main-box-1" class="main-box border-top">
<div class="main-box-inside">
<p class="no-modules-msg">No posts match your criteria. Please choose different options.</p>
</div>
</div>
<div id="main-box-2" class="main-box border-top ">
<h3 class="main-box-title">More Stuff</h3>
<div class="main-box-inside">
</div>
</div>
</div>
</div>
And my script:
(function($) {
$("document.body").ready(function() {
$("p.no-modules-msg")
.closest(".main-box")
.remove(".main-box")
})
})(jQuery);
It's working correctly in fiddle, but not on the live site...
https://jsfiddle.net/y90gtt6t/
The reason it's not working on your site, is because the documentation is quite clear, only the document has a ready handler
jQuery(document).ready(function($) {
$("p.no-modules-msg").closest(".main-box").remove()
});
Your use of "document.body" actually looks for an element like <document class="body"></document>, which it hopefully never finds.
Update: I have changed my JavaScript code, and I am now receiving errors in my iPhone Debug Console.
Disclaimer: I'm new to web development, and I'm not too good with JavaScript.
Scenario: I'm building an event calendar with CodeIgniter, and I'm hiding elements on mobile devices that need to be displayed elsewhere on the page when an event occurs. The elements being hidden are <ul>s, and they need to be displayed on another portion of the page when their cooresponding <span>s with the class .day_listing_mobile are selected. I've been working with different methods, but I haven't been able to find a solution out for hours as I'm not strong in the realm of jQuery/Ajax/JavaScript.
Question: What methods would be required to make the hidden <ul>s be displayed on a different portion of the page when their corresponding <span>s are selected?
JavaScript (Updated):
(function($) {
var isMobile = (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));
if (isMobile) {
$('.event_list').hide(); // setting display:none; on all .event_list <ul> elements
// attach click event to the <span class="day_listing"> elements
$('.day_listing_mobile').click(function() {
var eventList = $(this).sibling('.event_list').clone();
$(this).sibling('.event_list').remove();
$('#mobile_show_content').append(eventList);
});
}
})(jQuery);
I'm Receiving this error on this line of code var $eventList = $(this).sibling('.event_list').clone(); :
CodeIgniter Calendar Template (Controller):
{cal_cell_content}
<span class="day_listing_mobile">
{day}
</span>
<ul class="event_list">
{content}
</ul>
{/cal_cell_content}
{cal_cell_content_today}
<span class="day_listing_mobile" id="today_listing">
{day}
</span>
<ul class="event_list">
{content}
</ul>
{/cal_cell_content_today}
View:
<div class="row">
<div class="twelve columns">
<?php echo $calendar; ?>
</div>
</div>
<div class="show-on-phones">
<div class="row">
<div class="twelve columns" id="mobile_show_content">
<!--I want the <ul>s to show up here-->
</div>
</div>
</div>
Note that the CodeIgniter calendar class generates above where I want to display the <ul>s.
Just modify your click event to move the data around the dom.
$('.day_listing_mobile').click(function() {
var eventList = $(this).sibling('.event_list').clone();
$(this).sibling('.event_list').remove();
$('.mobile_show_content').append(eventList);
});
You can remove the node from the DOM and re-append it in a different place. (.remove() and .append())
But, rather than trying to solve this in javascript, why not design your page with adaptability in mind using css selectors to reflow the page at certain view port widths.
Check this out:
http://www.alistapart.com/articles/responsive-web-design/