Angular8 Drag and drop without any external plugin - drag-and-drop

I need suggestion. Currently working on [ angular 8 ] project.
I have to develop drag and drop widgets without using any external plugin ex
gridster etc..
How to achieve it ?
And how to store drag and drop of widgets preferences in database, so that i can see my widgets accordingly after log-in.

You will need to bind the data to the widgets in order to get them to retain the data after moving them around, resizing them, and/or closing out of the app and re-opening.
Angular, .Net, .Aspx are where you need to start.
Binding data without these type technologies is not possible.
You can do it with local storage using other technologies like jQuery Mobile, JavaScript, etc., but that data is lost.

I tried to write custom drag and drop along with clickable file upload using Angular without Plugin or any 3rd party Libraries.
Please feel free to reach me if any doubts.
The solution is as below:
1.Component.html
<div [ngClass]="{'col-md-12':!droppedFlag,'col-md-6':droppedFlag}" ngxDraganddrop (filesDropped)="handleDrop($event)">
<label class="custom-label w-100">Attach Files</label>
<div class="attach-file text-center">
<div class="row">
<label for="invoice_file_upload" style="margin-left: auto;margin-right: auto;">
<img src="./../../../../assets/images/file-download.png" height="36px" weight="27px" alt="">
</label>
<input type="file" style="display: none;" id="invoice_file_upload" #fileUpload
accept=".doc,.docx,.msg.csv,.pdf,.jpg,.png,.jpeg,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
placeholder="Select the type" (change)="onFileselected($event)" multiple>
</div>
<small class="custom-label" style="font-size: 12px;">Max. upload size 3 MB for each file <br> (Only
.png, .jpg, .jpeg, .csv, .xlsx, .xls, .pdf, .doc, .docx, .msg)</small>
</div>
<label class="pt-2" id="errorstatus"></label>
</div>
<div class="col-md-6 file_list_display">
<li *ngFor="let temp of temporarySelectedFile;let index = index" class="filename"><i
class="fa fa-check-circle text-success mr-2 col-md-1"></i>
<label class="col-md-10 padding_none">{{temp.name}}</label>
<i class="fa fa-trash text-danger ml-3 col-md-1" (click)="removeSelectedFile(index)"></i>
</li>
</div>
2.Create a Directive
import { Directive,EventEmitter,HostListener, Output } from '#angular/core';
#Directive({
selector: '[ngxDraganddrop]'
})
export class DraganddropDirective {
#Output() filesDropped=new EventEmitter<Event>()
// #Output() fileshovered=new EventEmitter
constructor() { }
#HostListener('drop',['$event'])onDrop($event: any){
$event.preventDefault();
let transfer=$event.dataTransfer;
this.filesDropped.emit(transfer.files);
//alert(transfer)
// this.fileshovered.emit(false);
}
#HostListener('dragover',['$event'])onDragOver($event: any){
$event.preventDefault();
// this.fileshovered.emit(true);
}
#HostListener('dragleave',['$event'])onDragLeave($event: any){
$event.preventDefault();
// this.fileshovered.emit(false);
}
}
3.component.ts
onFileselected(event) {
this.droppedFlag=1;
let allowedExtensions = /(\.jpg|\.jpeg|\.png|\.csv|\.xls|\.xlsx|\.pdf|\.doc|\.docx|\.msg)$/i;
if (this.allowedUploadFile == 0) {
event.target.value = "";
this.api.toastAlert('warning', 'Max 5 files allowed to upload');
this.droppedFlag=0;
return false;
} else if (this.allowedUploadFile < event.target.files.length) {
event.target.value = "";
this.api.toastAlert('warning', 'Max 5 files allowed to upload, You can select ' + this.allowedUploadFile + ' files or lesser.');
this.droppedFlag=0;
return false;
}
for (var i = 0; i < event.target.files.length; i++) {
if (!allowedExtensions.exec(event.target.files[i].name)) {
this.api.toastAlert('warning', 'Invalid file type');
return false;
} else {
this.selectedFile.push(event.target.files[i]);
this.temporarySelectedFile.push(event.target.files[i]);
this.allowedUploadFile -= 1;
}
}
}
handleDrop(event){
this.droppedFlag=1;
let allowedExtensions = /(\.jpg|\.jpeg|\.png|\.csv|\.xls|\.xlsx|\.pdf|\.doc|\.docx|\.msg)$/i;
for (var i = 0; i < event.length; i++) {
if (!allowedExtensions.exec(event[i].name)) {
this.api.toastAlert('warning', 'Invalid file type');
return false;
} else {
this.selectedFile.push(event[i]);
this.temporarySelectedFile.push(event[i]);
this.allowedUploadFile -= 1;
}
}
}
4.Before Upload
5.After Upload

Related

Angular 4 Load Data Service for Form throws ExpressionChangedAfterItHasBeenCheckedError

I'm getting data through an REST-API. With the help of this data I generate radio buttons for a form. As long as the form is not valid, the Submit-Button is disabled. Since retrieving the data takes a little time, the validity of the form changes. This throws an ExpressionChangedAfterItHasBeenCheckedError. How can I fix the problem? At the moment I'm a bit baffled.
Form:
<form #Form="ngForm" [formGroup]="formGroup">
<div formArrayName="formArray">
<div *ngFor="let temp of data,let i=index">
<label [for]="i">
<input [name]="i" type="radio" [formControlName]="i" [(ngModel)]="selection" [value]="temp"/>
{{temp.name}}
</label>
</div>
</div>
<buttontype="button" (click)="goToPrevious(Form)">Back</button>
<button mat-raised-button type="button" [disabled]="!formGroup.valid"
(click)="goToNext(Form)">Next
</button>
</form>
Component:
this.formGroup = new FormGroup({
formArray: this.formArray = new FormArray([])
});
this.commonService.getData().subscribe(data => {
this.data= data;
this.createForm();
}
);
createForm() {
for (let i = 0; i < this.data.length; i++) {
this.formArray.push(new FormControl('', [Validators.required]))
}
}
You can show the view only when all data is fetched using boolean flag, it should prevent the error, like this:
<form #Form="ngForm" [formGroup]="formGroup" *ngIf="readyToShow">
And in component:
readyToShow = false;
createForm() {
for (let i = 0; i < this.data.length; i++) {
this.formArray.push(new FormControl('', [Validators.required]))
}
this.readyToShow = true;
}

angular 2, validate form if at least one input is typed

I'm quite new to Angular, and I've already searched the web, without finding a correct solution for my situation.
I have a dynamic form created by a *ngFor. I need to disabled the submit button if the inputs are all empty and show the alert div; but I need to enable the submit if at least one of those forms contains something different from ''.
Here is my html code
<form class="form-inline" #form="ngForm">
<div class="form-group" *ngFor="let meta of state.metaById; let i = index" style="margin: 5px">
<label>{{meta.nome}}</label>
<input type="text" class="form-control" #nome (blur)="inputInArray(nome.value, i);">
</div>
<button type="button" class="btn btn-primary" (click)="getCustomUnitaDocumentaliRow(this.param)" [disabled]="fieldNotCompiled">invia</button>
</form>
<div class="alert-notification" [hidden]="!fieldNotCompiled">
<div class="alert alert-danger">
<strong>Va compilato almeno un campo.</strong>
</div>
</div>
and here is my Typescript code
inputInArray(nome: string, indice) {
if (this.state.controlloMetaId = true) {
this.state.metadatoForm[indice] = nome;
}
// this.fieldNotCompiled = false;
for (const i in this.state.metaById) {
console.log(this.state.metadatoForm);
if (isUndefined(this.state.metadatoForm[i]) || this.state.metadatoForm[i] === '') {
this.fieldNotCompiled = true && this.fieldNotCompiled;
} else {
this.fieldNotCompiled = false && this.fieldNotCompiled;
}
console.log(this.fieldNotCompiled);
}
With this code I can check the first time a user type something in one input, but it fails if it empty one of them (or all of them)
Thanks for your time
UPDATE
Check if any input got a change that is different from empty or space, just by doing:
<input ... #nome (input)="fieldNotCompiled = !nome.value.trim()" ....>
DEMO
You can set a listener to the form changes:
#ViewChild('form') myForm: NgForm;
....
ngOnInit() {
this.myForm.valueChanges.subscribe((value: any) => {
console.log("One of the inputs has changed");
});
}

Make form dynamicly add input with number

can anyone make these functions simple?
i have a ul:
<ul class="phone-type">
<li class="office" id="1"></li>
<li class="mobile" id="2"></li>
<li class="fax" id="3"></li>
</ul>
and the JS :
var o = 0;var m = 0;var f = 0;
$('ul.phone-type li.office').click(function () {
o++;
$('.phones').append('<input class="form-control phone_type" placeholder="'+ $(this).text()+'-'+o+'" name="phone['+$(this).attr('class')+'-'+o+']" type="text" ><br>');
});
$('ul.phone-type li.mobile').click(function () {
m++;
$('.phones').append('<input class="form-control phone_type" placeholder="'+ $(this).text()+'-'+m+'" name="phone['+$(this).attr('class')+'-'+m+']" type="text" ><br>');
});
$('ul.phone-type li.fax').click(function () {
f++;
$('.phones').append('<input class="form-control phone_type" placeholder="'+ $(this).text()+'-'+f+'" name="phone['+$(this).attr('class')+'-'+f+']" type="text" ><br>');
});
i have to reset it for every li..
is there any way that i can make it simple!!!!
tnx
This method will allow for an indefinite number of clickable list elements. Just ensure that you provide the 'data-type' attribute in any elements that are included.
When storing data in an html element, it is usually best to use the 'data' attribute. Using classes only works when there is one class.
HTML
<ul class="phone-type">
<li data-type="office" id="1">office</li>
<li data-type="mobile" id="2">mobile</li>
<li data-type="fax" id="3">fax</li>
</ul>
<div class="phones"></div>
JS
// This object will contain how many clicks each element has
var typeClicks = {};
$('ul.phone-type li').click(function() {
var li = $(this),
type = li.data('type'),
text = li.text(),
clicks;
// check if typeClicks contains any click data for this element
if (typeClicks.hasOwnProperty(type)) {
// if it does, increases tracked clicks by one
typeClicks[type]++;
clicks = typeClicks[type];
} else {
// if not, this will create an entry for this element
clicks = typeClicks[type] = 1;
}
// if not, this will create an entry for this element
$('.phones').append('<input class="form-control phone_type" placeholder="'+text+'-'+clicks+'" name="phone['+type+'-'+clicks+']" type="text" ><br>');
});

SharpSpring - Prevent form from automatically appearing if user has filled out form (without relying on cookies)

Ok, this is related to the question I asked a short while ago: Silverstripe/PHP/jQuery - Once form has been filled out by user, prevent it from automatically appearing for each visit
Something has changed since then. Per request of the client, the form must not automatically appear if the user has already filled it out and has thus been placed into SharpSpring. Originally, I was creating a cookie on successful form submission using JavaScript. However, the latest concern is that it's not effective enough as cookies are registered only to certain devices and browsers, and users can clear their cookies at any time.
Essentially, the desired result is to prevent the form from automatically appearing if the user has been registered in SharpSpring (a separate domain) without having to rely on cookies.
Has anyone ever attempted something like this, checking to see if a user has submitted a form to another domain?
For reference, here is the form code I have setup:
<?php
/*
Plugin Name: SharpSpring Form Plugin
Description: A custom form plugin that is SharpSpring-compatible and uses HTML, CSS, jQuery, and AJAX
Version: 1.0
*/
define('SSCFURL', WP_PLUGIN_URL . "/" . dirname(plugin_basename(__FILE__)));
define('SSCFPATH', WP_PLUGIN_DIR . "/" . dirname(plugin_basename(__FILE__)));
function sharpspringform_enqueuescripts()
{
wp_enqueue_script('jquery-src', SSCFURL . '/js/jquery.js', array('jquery'));
wp_enqueue_script('jquery-ui', SSCFURL . '/js/jquery-ui.js', array('jquery'));
wp_enqueue_script('boootstrap', SSCFURL . '/js/bootstrap.js', array('jquery'));
wp_localize_script('sharpspringform', 'sharpspringformajax', array('ajaxurl' => admin_url('admin-ajax.php')));
}
add_action('wp_enqueue_scripts', 'sharpspringform_enqueuescripts');
function sharpspringform_show_form()
{
wp_enqueue_style( 'boilerplate', SSCFURL.'/css/boilerplate.css');
wp_enqueue_style( 'bootstrapcss', SSCFURL.'/css/bootstrap.css');
wp_enqueue_style( 'bookregistration', SSCFURL.'/css/Book-Registration.css');
wp_enqueue_style( 'formstyles', SSCFURL.'/css/styles.css');
?>
<div class="mobile-view" style="right: 51px;">
<a class="mobile-btn">
<span class="glyphicon glyphicon-arrow-left icon-arrow-mobile mobile-form-btn"></span>
</a>
</div>
<div class="slider register-photo">
<div class="form-inner">
<div class="form-container">
<form method="post" enctype="multipart/form-data" class="signupForm" id="browserHangFormPV">
<a class="sidebar">
<span class="glyphicon glyphicon-arrow-left icon-arrow arrow"></span>
</a>
<a class="closeBtn">
<span class="glyphicon glyphicon-remove"></span>
</a>
<h2 class="text-center black">Sign up for our newsletter.</h2>
<p class="errors-container light">Please fill in the required fields.</p>
<div class="success">Thank you for signing up!</div>
<div class="form-field-content">
<div class="form-group">
<input class="form-control FirstNameTxt" type="text" name="first_name" placeholder="*First Name"
autofocus="">
</div>
<div class="form-group">
<input class="form-control LastNameTxt" type="text" name="last_name" placeholder="*Last Name"
autofocus="">
</div>
<div class="form-group">
<input class="form-control EmailTxt" type="email" name="email" placeholder="*Email"
autofocus="">
</div>
<div class="form-group">
<input class="form-control CompanyTxt" type="text" name="company" placeholder="*Company"
autofocus="">
</div>
<div class="form-group submit-button">
<button class="btn btn-primary btn-block button-submit" type="button">SIGN ME UP</button>
<img src="/wp-content/plugins/sharpspring-form/img/ajax-loader.gif" class="progress" alt="Submitting...">
</div>
</div>
<br/>
<div class="privacy-link">
<a href="[privacy policy link]" class="already" target="_blank"><span
class="glyphicon glyphicon-lock icon-lock"></span>We will never share your information.</a>
</div>
</form>
<input type="hidden" id="gatewayEmbedID" value="<?php echo get_option( 'pv_signup_sharpspring_ID' ); ?>" />
<script type="text/javascript">
var embedID = document.getElementById("gatewayEmbedID").value;
var __ss_noform = __ss_noform || [];
__ss_noform.push(['baseURI', 'https://app-3QNAHNE212.marketingautomation.services/webforms/receivePostback/[redacted]']);
__ss_noform.push(['form', 'browserHangFormPV', embedID]);
__ss_noform.push(['submitType', 'manual']);
</script>
<script type="text/javascript" src="https://koi-3QNAHNE212.marketingautomation.services/client/noform.js?ver=1.24" ></script>
</div>
</div>
</div>
<?php
}
function sharpspringform_shortcode_func( $atts )
{
ob_start();
sharpspringform_show_form();
$output = ob_get_contents();
ob_end_clean();
return $output;
}
add_shortcode( 'sharpspringform', 'sharpspringform_shortcode_func' );
The form submission code with generates a cookie using JS:
;
(function ($) {
$(document).ready(function () {
var successMessage = $('.success');
var error = $('.errors-container');
var sharpSpringID = $('#gatewayEmbedID').val();
var submitbtn = $('.button-submit');
var SubmitProgress = $('img.progress');
var formdata = {};
function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
submitbtn.click(function (e) {
resetErrors();
postForm();
});
function resetErrors() {
$('.signupForm input').removeClass('error-field');
}
function postForm() {
$.each($('.signupForm input'), function (i, v) {
if (v.type !== 'submit') {
formdata[v.name] = v.value;
}
});
submitbtn.hide();
error.hide();
SubmitProgress.show();
$.ajax({
type: "POST",
data: formdata,
url: '/wp-content/plugins/sharpspring-form/sharpsring-form-submission.php',
dataType: "json"
}).done(function (response) {
submitbtn.show();
SubmitProgress.hide();
if (response.errors) {
error.show();
var errors = response.errors;
errors.forEach(function (error) {
$('input[name="' + error + '"]').addClass('error-field');
})
}
else {
__ss_noform.push(['submit', null, sharpSpringID]);
setCookie('SignupSuccess', 'NewsletterSignup', 3650);
$('#browserHangFormPV')[0].reset();
$('.form-field-content').hide();
successMessage.show();
$('.button-submit').html("Submitted");
}
});
}
});
}(jQuery));
The jQuery code that sets up the form sliding animation and popup feature, as well as checks for the existence of the JS cookie created on successful form submit:
jQuery.noConflict();
(function ($) {
$(document).ready(function () {
//This function checks if we are in mobile view or not to determine the
//UI behavior of the form.
checkCookie();
window.onload = checkWindowSize();
var arrowicon = $(".arrow");
var overlay = $("#overlay");
var slidingDiv = $(".slider");
var closeBtn = $(".closeBtn");
var mobileBtn = $(".mobile-btn");
//When the page loads, check the screen size.
//If the screen size is less than 768px, you want to get the function
//that opens the form as a popup in the center of the screen
//Otherwise, you want it to be a slide-out animation from the right side
function checkWindowSize() {
if ($(window).width() <= 768) {
//get function to open form at center of screen
if(sessionStorage["PopupShown"] != 'yes' && !checkCookie()){
setTimeout(formModal, 5000);
function formModal() {
slidingDiv.addClass("showForm")
overlay.addClass("showOverlay");
overlay.removeClass('hideOverlay');
mobileBtn.addClass("hideBtn");
}
}
}
else {
//when we aren't in mobile view, let's just have the form slide out from the right
if(sessionStorage["PopupShown"] != 'yes' && !checkCookie()){
setTimeout(slideOut, 5000);
function slideOut() {
slidingDiv.animate({'right': '-20px'}).addClass('open');
arrowicon.addClass("glyphicon-arrow-right");
arrowicon.removeClass("glyphicon-arrow-left");
overlay.addClass("showOverlay");
overlay.removeClass("hideOverlay");
}
}
}
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function checkCookie() {
var user = getCookie("SignupSuccess");
if (user != "") {
return true;
} else {
return false;
}
}
/*
------------------------------------------------------------
Functions to open/close form like a modal in center of screen in mobile view
------------------------------------------------------------
*/
mobileBtn.click(function () {
slidingDiv.addClass("showForm");
slidingDiv.removeClass("hideForm");
overlay.addClass("showOverlay");
overlay.removeClass('hideOverlay');
mobileBtn.addClass("hideBtn");
});
closeBtn.click(function () {
slidingDiv.addClass("hideForm");
slidingDiv.removeClass("showForm");
overlay.removeClass("showOverlay");
overlay.addClass("hideOverlay")
mobileBtn.removeClass("hideBtn");
sessionStorage["PopupShown"] = 'yes'; //Save in the sessionStorage if the modal has been shown
});
/*
------------------------------------------------------------
Function to slide the sidebar form out/in
------------------------------------------------------------
*/
arrowicon.click(function () {
if (slidingDiv.hasClass('open')) {
slidingDiv.animate({'right': '-390px'}, 200).removeClass('open');
arrowicon.addClass("glyphicon-arrow-left");
arrowicon.removeClass("glyphicon-arrow-right");
overlay.removeClass("showOverlay");
overlay.addClass("hideOverlay");
sessionStorage["PopupShown"] = 'yes'; //Save in the sessionStorage if the modal has been shown
} else {
slidingDiv.animate({'right': '-20px'}, 200).addClass('open');
arrowicon.addClass("glyphicon-arrow-right");
arrowicon.removeClass("glyphicon-arrow-left");
overlay.addClass("showOverlay");
overlay.removeClass("hideOverlay");
}
});
});
}(jQuery));
I'm confused by the WordPress code here, rather than SilverStripe, it's not clear in your question which platform you're using.
Basically, if you want something more robust than cookies, you'll need to store the registration in the database and check it there (assuming the registration form is on your site). This means you handle the form submission on your site, send the data to the remote site and check the responses, and if all goes well, save the fact that the user has registered remotely into your database where you can check when deciding whether to show the form or not, next time.
If you don't have access to the registration form, or you want to also notice registrations made independently of your site, then you need to have an API you can query on the remote site in order to see if the user is registered.
I found a sharpspring API, but I'm not sure if it's relevant.

jQuery Isotope Filtering Reset

I'm using JQuery Isotope with a combination, three-level filter. In all the examples I've come across, the only way to "reset" the filters is by clicking a "Show All" option.
Is it possible to "un-filter" results by clicking on a selected filter to un-select it?
Here is an example: http://jsfiddle.net/RevConcept/suagb/
Here is my code...
HTML
<div id="options" class="combo-filters">
<div class="option-combo location">
<ul class="filter option-set group level-one" data-filter-group="location">
<li class="hidden">any
<li>exterior
<li>interior
</ul>
</div>
<div class="option-combo illumination">
<ul class="filter option-set group level-two" data-filter-group="illumination">
<li class="hidden">any
<li>illuminated
<li>non-illuminated
</ul>
</div>
<div class="option-combo mount">
<ul class="filter option-set group level-three" data-filter-group="mount">
<li class="hidden">any
<li>wall
<li>ground
</ul>
</div>
</div><!--end options-->
CSS
header nav a {
color:#666666;
}
header nav a.selected {
color:#000000;
}
JAVASCRIPT
$(function(){
var $container = $('#container'),
filters = {};
$container.isotope({
itemSelector : '.project',
masonry: {
columnWidth: 80
}
});
// filter buttons
$('.filter a').click(function(){
var $this = $(this);
// don't proceed if already selected
if ( $this.hasClass('selected') ) {
return;
}
var $optionSet = $this.parents('.option-set');
// change selected class
$optionSet.find('.selected').removeClass('selected');
$this.addClass('selected');
// store filter value in object
// i.e. filters.location = 'exterior'
var group = $optionSet.attr('data-filter-group');
filters[ group ] = $this.attr('data-filter-value');
// convert object into array
var isoFilters = [];
for ( var prop in filters ) {
isoFilters.push( filters[ prop ] )
}
var selector = isoFilters.join('');
$container.isotope({ filter: selector });
return false;
});
});
You could add a "Reload Page" button...
Here are 3 examples for you...
<input type="button" value="Reload Page" onClick="window.location.href=window.location.href">
<input type="button" value="Reload Page" onClick="window.location.reload()">
<input type="button" value="Reload Page" onClick="history.go(0)">
isoSelective provides combining and toggling filters. Try using my updated version: https://github.com/simmerdesign/jquery-isoselective