Ar.js on SvelteKit Webcam Resizing problem - webcam

I am running an AR application inside Sveltekit with aFrame and AR.js. At the moment everything is working fine. I can read the bookmark and load a virtual element. My problem is that AR.js adjusts the html body to a larger size than it is and does not adapt if I change the screen size. Any help is welcome.
<script>
//componente para sombra en camera background
AFRAME.registerComponent("apply-shadowmaterial", {
init: function() {
// grab the mesh
let mesh = this.el.getObject3D("mesh");
// keep the reference to the old material
let tmp = mesh.material;
// assign the new material
mesh.material = new THREE.ShadowMaterial({ opacity: 0.1 });
mesh.receiveShadow = true;
// free memory
tmp.dispose();
}
});
</script>
<a-scene id="escena" class="a-frame" gesture-detector physicallyCorrectLights="true" vr-mode-ui="enabled: false" embedded arjs ="sourceType: webcam; trackingMethod: best; detectionMode: mono; sourceWidth:2048; sourceHeight:1536; displayWidth: 2048; displayHeight: 1536" always-fullscreen renderer="precision: high; antialias: false; logarithmicDepthBuffer:true; colorManagement: true" loading-screen="dotsColor: #DBDADA; backgroundColor: #282828">
<a-assets>
<a-asset-item id="blackM" src={`${storeData.assets.vectorFile}`}></a-asset-item>
</a-assets>
<a-entity id="luzdirectional" light="type: directional; color: #DDD; groundColor: #DDD; intensity: 0.2; castShadow:true; target:#marcador; shadowCameraBottom:-6.0; shadowCameraTop:6.0; shadowCameraLeft:-6.0; shadowCameraRight:6.0; " position="-5.0 6.520 5.127">
</a-entity>
<a-marker id="marcador" raycaster="objects: .clickable" emitevents="true" cursor="fuse: false; rayOrigin: mouse;" type='pattern' url='/hiro.patt' smooth='true' smoothCount='3' smoothTolerance='0.01' smoothThreshold='2'>
<a-plane id="planosombras" position="0 -0.2 0" height="500" width="500" rotation="-90 0 0" apply-shadowmaterial></a-plane>
<a-entity
id="plato"
position="0 0 0"
rotation="0 60 0"
scale="0.1 0.1 0.1"
gltf-model={`${storeData.assets.vectorFile}`}
shadow="receive: true; cast: true"
animation__pos="property:position; from:0 0 0; to:-6 0 0; dur: 1000; startEvents:pos"
animation__scale="property:scale; from:0.1 0.1 0.1; to:0 0 0; dur: 1000; startEvents:scale"
class="clickable"
gesture-handler
>
</a-entity>
</a-marker>
<a-entity id="camera" camera="far:10000.00; fov:80.00; near:0.005">
</a-entity>
<a-entity id="luz" light="type: ambient; color: #DDD; groundColor: #DDD; intensity: 0.6" position="0 2 0">
</a-entity>
</a-scene>
<div class="nav">
<!-- <button class="btn left" onclick="backPlatillo()">❮</button>
<button class="btn right" onclick="nextPlatillo()">❯</button> -->
<div class="prod-name" id="platilloName">{storeData.title}</div>
</div>

Related

Data is not coming if i use async in vue js 3

I am implementing Quiz App but here I am facing an issue if I put static data in array the questions are coming.
Data is not coming if i use async in Vue JS 3
But If I Call data from the API the questions are not showing.
when I console the questions are showing in console and not showing in the front end.
For ref please find the attached code and image.
Home.vue (please see fetchQuestionsFromServer function)
<template>
<main class="flex h-screen items-center justify-center bg-gray-100">
<!-- quiz container -->
<QuizComplatePage v-if="endofQuiz" />
<div
class="overflow-hidden bg-white flex-none container relative shadow-lg rounded-lg px-12 py-6"
>
<img
src="#/assets/images/abstract.svg"
alt=""
class="absolute -top-10 left-0 object-none"
/>
<!-- contents -->
<div class="relative z-20">
<!-- score container -->
<div class="text-right text-gray-800">
<p class="text-sm leading-3">Score</p>
<p class="font-bold">{{score}}</p>
</div>
<!-- timer container -->
<div class="bg-white shadow-lg p-1 rounded-full w-full h-5 mt-4">
<div class="bg-blue-700 rounded-full w-11/12 h-full"
:style= "`width: ${timer}%`"
></div>
</div>
<!-- question container -->
<div
class="rounded-lg bg-gray-100 p-2 neumorph-1 text-center font-bold text-gray-800 mt-8"
>
<div class="bg-white p-5">
{{currentQuestion.question}}
</div>
</div>
<!-- options container -->
<div class="mt-8">
<!-- option container -->
<div v-for="(choice,item) in currentQuestion.choices" :key="item">
<div
class="neumorph-1 option-default bg-gray-100 p-2 rounded-lg mb-3 relative"
:ref="optionchosen"
#click="onOptionClick(choice,item)"
>
<div
class="bg-blue-700 p-1 transform rotate-45 rounded-md h-10 w-10 text-white font-bold absolute right-0 top-0 shadow-md"
>
<p class="transform -rotate-45">+10</p>
</div>
<div class="rounded-lg font-bold flex p-2">
<!-- option ID -->
<div class="p-3 rounded-lg">{{item}}</div>
<!-- option name -->
<div class="flex items-center pl-6">{{choice}}</div>
</div>
</div>
</div>
<!-- option container -->
</div>
<!-- progress indicator container -->
<div class="mt-8 text-center">
<div class="h-1 w-12 bg-gray-800 rounded-full mx-auto"></div>
<p class="font-bold text-gray-800">{{questionCounter}}/{{questions.length}}</p>
</div>
</div>
</div>
</main>
</template>
<script>
import { onMounted, ref } from 'vue'
import QuizComplatePage from './QuizCompleteOverlay.vue'
export default{
components: {
QuizComplatePage
},
setup(){
//data
let canClick = true
let score = ref(0)
let timer = ref(100)
let endofQuiz = ref(false)
let questionCounter = ref(0)
const currentQuestion = ref({
question: '',
answer: 1,
choices: [],
});
const questions = []
const loadQuestion = () =>{
canClick = true
timer.value=100
//Check question array had questions or not
if(questions.length > questionCounter.value){
currentQuestion.value = questions[questionCounter.value]
console.log('Current Question is : ', currentQuestion.value);
questionCounter.value++
}else{
endofQuiz.value = true
console.log('Out of Questions');
}
}
//methods
let itemsRef = []
const optionchosen = (element) =>{
if(element){
itemsRef.push(element)
}
}
const clearSelected = (divselected) =>{
setTimeout(()=>{
divselected.classList.remove('option-correct')
divselected.classList.remove('option-wrong')
divselected.classList.add('option-default')
loadQuestion()
},1000)
}
const onOptionClick = (choice,item) =>{
if(canClick)
{
const divContainer = itemsRef[item]
const optionId = item+1
if(currentQuestion.value.answer ===optionId){
console.log('You are Correct');
score.value += 10
divContainer.classList.add('option-correct')
divContainer.classList.remove('option-default')
}else{
console.log('You are Wrong');
divContainer.classList.add('option-wrong')
divContainer.classList.remove('option-default')
}
timer.value=100
canClick=false
//to go next question
clearSelected(divContainer)
console.log(choice,item);
}else{
console.log('Cant Select Option');
}
}
const countDownTimer = () =>{
let interval= setInterval(()=>{
if(timer.value>0){
timer.value--
}else{
console.log('Time is over');
clearInterval(interval)
}
},150)
}
const fetchQuestionsFromServer = async function(){
fetch('https://opentdb.com/api.php?amount=10&category=18&type=multiple')
.then((res) =>{
return res.json()
})
.then((data) =>{
const newQuestions = data.results.map((serverQuestion) =>{
const arrangedQuestion = {
question: serverQuestion.question,
choices: '',
answer: ''
}
const choices = serverQuestion.incorrect_answers
arrangedQuestion.answer = Math.floor(Math.random() * 4 + 1)
choices.splice(arrangedQuestion.answer-1 , 0 , serverQuestion.correct_answer)
arrangedQuestion.choices = choices
return arrangedQuestion
})
console.log('new formated questions' , newQuestions);
questions.value = newQuestions
loadQuestion()
countDownTimer()
console.log('questions: =>' , questions.value);
})
}
//lifecycle hooks
onMounted(() =>{
fetchQuestionsFromServer()
})
//return
return {
timer,
currentQuestion,
questions,
score,
questionCounter,
loadQuestion,
onOptionClick,
optionchosen,
endofQuiz,
}
}
}
</script>
<style scoped>
.neumorph-1 {
box-shadow: 6px 6px 18px rgba(0, 0, 0, 0.09), -6px -6px 18px #ffffff;
}
.container {
max-width: 400px;
border-radius: 25px;
}
</style>
QuizComplatePage.vue
<template>
<div class="w-screen h-screen absolute z-30 bg-white bg-opacity-30 flex justify-center items-center">
<div class="bg-green-700 p-4 text-center text-white">
<p class="font-bold text-2xl">All DOne!</p>
<p class="my-4 font-bold text-3xl">100% Score</p>
<!-- Buttons -->
<div class="flex justify-center">
<div class="rounded-full py-1 w-28 border cursor-pointer hover:text-black hover:bg-white">Done</div>
<div class="rounded-full py-1 w-28 border cursor-pointer hover:text-black hover:bg-white">Retry</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'QuizComplatePage'
}
</script>
<style>
</style>
Image.
You are not using value when you need to:
For instance look in this function
questions.length should be questions.value.length
Also currentQuestion.value = questions.value[questionCounter.value]
Start by fixing that.
Everything that is a ref in your setup needs to be accessed by .value in anything inside your setup. Outside your setup it will have this and can be treated normally. Mixing these two up is the most common error.
const loadQuestion = () =>{
canClick = true
timer.value=100
//Check question array had questions or not
if(questions.value.length > questionCounter.value){
currentQuestion.value = questions.value[questionCounter.value]
console.log('Current Question is : ', currentQuestion.value);
questionCounter.value++
}else{
endofQuiz.value = true
console.log('Out of Questions');
}
}
Here is my solution
let questions = []
questions = newQuestions
Now I am able to load questions.

VueJS file upload field cannot be reset

In my vuejs application, I have a modal to insert some user data with a file upload.
I should be able to clear all the form fields once when an user successfully upload any content.
All my fields get reset apart from the file upload field.
It will remained as it is.
Inside my form.vue, for the file upload I have
<div class="mb-1">
<dashboard-input-label
identifier="document"
:settings="{ help: true, helpDirection: 'left' }"
>
Upload document
<template slot="helpText">
Maximum filesize is 5 MB. The default allowed file extensions
are: pdf, jpeg and png.
</template>
</dashboard-input-label>
<validator-v2
:identifier="identifier"
name="document_file"
:rules="{ required: { message: 'Document is required.' } }"
>
<custom-file-upload
ref="documentDocument"
v-model="documentFile"
:max-upload-file-size="5"
name="document_file"
></custom-file-upload>
</validator-v2>
</div>
and following is my button
<loading-button ref="submitBtn" size="normal">
Save & Add new
</loading-button>
This is my submitBtn method,
storeDocumentAndAddNew() {
this.isAddNew = true
const loader = this.$refs.submitBtn
this.storeDocument(loader)
},
And for the field reset I have followings,
reset() {
this.documentName= null
this.dateOfIssue= null
this.expiryDate= null
this.documentNumber = null
this.doesNotHaveDocumentNumber = false
this.doesNotExpire = false
this.documentFile = null
this.doesOptIn = false
this.isAddNew = false
this.documentFile = ''
this.$refs.documentDocument.value = null
},
Once I hit submit, every field get reset except this file upload field.
Following is my custom-file-upload.vue component
<template>
<div>
<div class="flex items-center flex-wrap">
<div #click="selectFile" class="flex items-center cursor-pointer w-full form-input custom-file-upload ">
<p class="flex justify-between items-center w-full overflow-hidden">
<span class="font-regular text-base flex items-center justify-center">
<span v-if="filename !== null">{{ filename | limitString }} </span>
<span class="cs--file-upload-current-file overflow-hidden inline-block" v-else><slot
name="currentFile"></slot></span>
</span>
<span class="text-certstyle-text-light ">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-upload"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline
points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>
</span>
</p>
<input #change="showFileName" ref="fileInput" type="file" :name="name">
<div class="flex flex-col fixed top-0 right-0 z-50">
<toastr-alert #hidden="resetToastrMessage" v-if="message !== ''" :message="message"
:type="type"></toastr-alert>
</div>
</div>
</div>
</div>
</template>
Even though I've used, this.$refs.documentDocument.value = null it's not clearing my file upload field....
Update
I have used #wendt88's answer and then the file is removed. But the previously uploaded, document's name will be remained there as it is..As an example, if I tried to upload a document called, dummy.pdf, it'll show the dummy.pdf text even after a successful submission...
Now my reset looks likes this,
reset() {
this.documentName= null
this.dateOfIssue= null
this.expiryDate= null
this.documentNumber = null
this.doesNotHaveDocumentNumber = false
this.doesNotExpire = false
this.documentFile = null
this.doesOptIn = false
this.isAddNew = false
this.$refs.documentDocument.$refs.fileInput.value = null
},
Following is my complete custom-file-upload.vue
<template>
<div>
<div class="flex items-center flex-wrap">
<div #click="selectFile" class="flex items-center cursor-pointer w-full form-input custom-file-upload ">
<p class="flex justify-between items-center w-full overflow-hidden">
<span class="font-regular text-base flex items-center justify-center">
<span v-if="filename !== null">{{ filename | limitString }} </span>
<span class="cs--file-upload-current-file overflow-hidden inline-block" v-else><slot
name="currentFile"></slot></span>
</span>
<span class="text-certstyle-text-light ">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-upload"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline
points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>
</span>
</p>
<input #change="showFileName" ref="fileInput" type="file" :name="name">
<div class="flex flex-col fixed top-0 right-0 z-50">
<toastr-alert #hidden="resetToastrMessage" v-if="message !== ''" :message="message"
:type="type"></toastr-alert>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.custom-file-upload input {
position: absolute;
cursor: pointer;
height: 0;
width: 0;
opacity: 0;
}
.cs--file-upload-current-file {
max-width: 220px;
}
label {
font-weight: 400 !important;
}
</style>
<script>
// Mixins
import HasToastrMessage from '#/Mixins/HasToastrMessage.js';
// Helper
import Helper from '#/Support/Helper.js';
export default {
mixins: [HasToastrMessage],
props: ['name', 'value', 'maxUploadFileSize'],
data() {
return {
file: null,
filename: null,
message: "",
type: "",
fileSize: 0,
maxFileSize: 10,
validFileTypes: [
'application/pdf',
'image/jpeg',
'image/png'
]
}
},
mounted() {
if (Helper.isset(this.maxUploadFileSize)) {
this.maxFileSize = this.maxUploadFileSize;
}
},
methods: {
showFileName(e) {
this.filename = collect(e.target.value.split('\\')).last();
let file = e.target.files[0];
let fileSize = file.size / 1000000;
if (fileSize > this.maxFileSize) {
this.showToastrErrorMessage(`The uploaded file is too big. Max size: ${this.maxFileSize} MB.`);
this.$refs.fileInput.value = null
this.filename = null
} else if (!this.validFileTypes.includes(file.type)) {
this.showToastrErrorMessage(`The uploaded file is invalid. Please upload valid type.`);
this.$refs.fileInput.value = null
this.filename = null
} else if (this.filename) {
this.file = file
this.showToastrSuccessMessage(`Your file is successfully uploaded.`);
this.$emit('uploaded')
} else {
this.showToastrErrorMessage(`Your file could not be uploaded. Please try again.`);
}
},
resetToastrMessage() {
this.message = "";
this.type = "";
},
selectFile() {
this.$refs.fileInput.click();
},
}
}
</script>
this.$refs.documentDocument is a vue component, to clear it´s value property use this.$set(this.$refs.documentDocument, 'value', null) -> https://v2.vuejs.org/v2/guide/reactivity.html
otherwise documentDocument does not know that you have changed it´s value
but if you want to clear the file input value, run (https://stackoverflow.com/a/16222877/1826106):
this.$refs.documentDocument.$refs.fileInput.value = null;
this.$set(this.$refs.documentDocument, 'filename', null);

How to add dialog/modal that asks if we want to delete something in vuejs2

So i have been looking on internet for some kinda of dialog/modal in vuejs2 that pops up when exit is clicked, that asks us if we are sure that we want to leave. And when click yes, function is called , and when clicked no, nothing happens just dialog/modal is exited. I was not able to find anything on the vuejs.org.Im not using bootstrap and not using vutify. Any suggestions how this can be done, that popup should blackout the rest of the screen and poput in the middle of the screen.
Its very easy to create your own dialog.
Here is a small component that I created for you.
https://jsfiddle.net/ew1c3z6u/
Im really new to veujs but this should work for you
var component =new Vue({
el: '#dialog-container',
methods:{
show:(event)=> {
component.visibility = true;
// maybe you could ajest the position of the dialog here.
// eg top, center etc
},
onSave:(event)=> {
alert("save clicked")
component.visibility = false;
},
onCancel:(event)=> {
alert("cancel clicked")
component.visibility = false;
}
},
data: {
buttons:[], // you could have a list a dynamic buttons here
content:"this is the content of the dialog",
visibility:false,
title: 'this is the title of the dialog'
}
})
.dimBackground{
background:black;
opacity:0.5;
z-index:90;
position:fixed;
width:100%;
height:100%;
left:0;
top:0;
}
#dialog-container > #dialog
{
background:white;
z-index:100;
min-width:400px;
min-height: 100px;
border:1px black solid;
display:inline-block;
padding:0;
position:fixed;
left:30%;
top:30%;
overflow-x:hidden;
overflow-y:auto;
}
#dialog-container > #dialog > h1{
width:99%;
background:blue;
color:white;
margin:0;
font-size:20px;
padding-top:5px;
padding-bottom:5px;
padding-left:5px;
}
#dialog-container > #dialog > .content{
padding:5px;
}
#dialog-container > #dialog > h1 > div{
display:inline-block;
float:right;
position:relative;
top:-3px;
padding-right:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script>
<div id="dialog-container">
<input type="button" value="show dialog" v-on:click="show" />
<div class="dimBackground" v-if=visibility> </div>
<div id="dialog" v-if=visibility>
<h1>
{{title}}
<div>
<button v-on:click="onSave" >
Save
</button>
<button v-on:click="onCancel">
Cancel
</button>
</div>
</h1>
<div class="content">
{{content}}
</div>
</div>
</div>

Two sortable items dragged if trying to move just one card from the sortable group

I have implemented sortablejs in Polymer2.0 element. I am able to drag and drop the item from group. The issue I am facing now is that randomly, not sure why and how, but 2 cards or items gets moved in a group list. Here's the screenshots.
todos is an object which contains group of lists which have array of items.
List
https://www.dropbox.com/s/9wp6vv668p3ckr2/Screenshot%202019-04-30%2007.18.16.png?dl=0
End state when dropped (you see 2 cards moved to the new column which I don't want. I only wanted one card to move)
https://www.dropbox.com/s/int4uyyl3945tjv/Screenshot%202019-04-30%2007.18.50.png?dl=0
Code: Polymer element html
<div class="board­__sprint">
<template is="dom-repeat" items="{{todos}}" as="row" restamp>
<div class="list">
<div class="list­-content">
<div style="float: left; width: 100%; text-align: center;">
<div style="float: left; width: 80%; text-align: left; padding-top: 10px;">
<h7 style="color: black; font-size: 20px; font-weight: 800; padding-left: 10px;margin-top: 5px;">
[[row.tasks.length]]
</h7>
<h7 style="color: black; font-size: 12px; font-weight: 200; padding: 2px; margin-top: 5px;">
[[row.title]]
</h7>
</div>
<div style="float: left; width: 20%; text-align: center;">
<paper-icon-button icon="icons:delete-sweep" style="color: grey;" id="deleteNote" row="[[row]]"
on-tap="_removeColumnTriggerDialog"></paper-icon-button>
</div>
</div>
<div style="display: table;">
<div style="width: 90%; height: 3px; background: #0c66b5;">
<h7> </h7>
</div>
<div id="myid[[row.id]]" class="list-group" style="min-height: 120px;">
<template is="dom-repeat" items="{{row.tasks}}" as="todo" restamp>
<!-- <div class$="{{determineDragable(todo)}}"> -->
<div class="item">
<div class="ticket" data-index$="{{todo.id}}">
<paper-card style="float:center; width: 100%;" class="singleColor" data-index$="{{todo}}"
data-index$="{{row}}">
<div style="float:left; width: 15%" style$="{{getRandomInt(0, 20)}}">
<h7> </h7>
</div>
<div style="width: 100%">
<div style="float: left; width: 15%; vertical-align:center">
<px-icon icon="px-vis:pin"></px-icon>
</div>
<div style="float: left; width: 70%">
<h7 class="banksTitle" style="color: black; font-size: 12px; text-align:left;">
<b>[{{index}}]</b> [[todo.actTitle]]
</h7>
<h7 class="banksTitle" style="color: grey; font-size: 12px; text-align:left;">
[[todo.actDesc]]
</h7>
</div>
<template is="dom-if" if="{{checkDummy(todo)}}">
<div style="float: left; width: 15%;">
<paper-icon-button icon="icons:close" style="color: grey;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap="_moveDel"></paper-icon-button>
</div>
</template>
<template is="dom-if" if="{{checkDummyNot(todo)}}">
<div style="float: left; width: 15%;">
<paper-icon-button icon="image:crop-square" style="color: grey;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</div>
</template>
</div>
<div>
<h5> </h5>
</div>
<div style="width: 100%;display: table;">
<div style="float: left; width: 15%;">
</div>
<div style="float: left; width: 70%; text-align: center;">
<template is="dom-if" if="{{checkDummy(todo)}}">
<paper-icon-button icon="av:playlist-add-check" style="color: green;"
id$="bt_readmore" todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</template>
<template is="dom-if" if="{{checkDummy(todo)}}">
<paper-icon-button icon="editor:attach-file" style="color: maroon;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</template>
<template is="dom-if" if="{{checkDummy(todo)}}">
<paper-icon-button icon="editor:border-color" style="color: grey;" id$="bt_readmore"
todo="[[todo]]" row="[[row]]" on-tap=""></paper-icon-button>
</template>
</div>
<div style="float: right; width: 15%;">
</div>
</div>
</paper-card>
</div>
</div>
</template>
</div>
</div>
<div>
<h5> </h5>
</div>
<div class="addTicket">
<paper-button raised class="blue" on-tap="_addTicketDialog" row={{row}}>Add Ticket</paper-button>
</div>
</div>
</div>
</template>
</div>
and the JS script specific to onAdd event of sortablejs
_todosChanged() {
setTimeout(() => {
console.log('this.todos.length = ' + this.todos.length);
var self = this;
if (this.todos !== null || this.todos !== undefined) {
var lowestOrder = 0;
var highestOrder = 0;
var options = {
group: 'shared',
animation: 200,
sort: false,
draggable: ".item",
onAdd: function (evt) {
console.log('---FROM----');
console.log(evt.from.id);
console.log('---TO----');
console.log(evt.to.id);
console.log('---ITEM----');
console.log(evt.item.innerText);
var foundFrom = false;
var fromId = evt.from.id.substr('myid'.length);
var fromCol;
var foundTo = false;
var toId = evt.to.id.substr('myid'.length);
var toCol;
console.log('fromId =' + fromId + ' toId =' + toId);
self.todos.forEach(child => { //todos = 1, 3, 4 & row = 3
if (!foundTo) {
if (child.id === toId) {
foundTo = true;
toCol = child;
}
}
if (!foundFrom) {
if (child.id === fromId) {
foundFrom = true;
fromCol = child;
}
}
});
console.log('toCol = ' + JSON.stringify(toCol));
console.log('fromCol = ' + JSON.stringify(fromCol));
//find item in from col
var str = evt.item.innerText;
var itemKey = str.substr(0, str.indexOf(':'));
itemKey = itemKey.substr(itemKey.indexOf('KEY-')).substr('KEY-'.length);
console.log('itemKey = ' + itemKey);
var arrItemToRemove = fromCol.tasks;
console.log('arrItemToRemove = ' + JSON.stringify(arrItemToRemove));
var indexItem = -1;
for (var i = 0; i < arrItemToRemove.length; i++)
if (arrItemToRemove[i].id === itemKey) indexItem = i;
console.log('indexItem = ' + indexItem);
if (indexItem < 0 || indexItem > arrItemToRemove.length) {
document.getElementById('toastError').show('No item found');
} else {
// console.log('indexItem=' + indexItem);
var newItemToPush = arrItemToRemove[indexItem];
console.log('newItemToPush=' + JSON.stringify(newItemToPush));
//now add the item to the right
var arr = toCol.tasks;
if (arr === null || arr === undefined) arr = [];
arr.push({
'actTitle': newItemToPush.actTitle,
'actDesc': newItemToPush.actDesc,
'actDt': newItemToPush.actDt,
'parent': toCol.order,
'id': newItemToPush.id
});
console.log('arr=' + JSON.stringify(arr));
self.$.query.ref.child(toCol.$key).child('tasks').set(arr);
var nwArr = arrItemToRemove.splice(indexItem, 1);
document.getElementById('toastShort').show('Data moved: ' + newItemToPush.actTitle);
self.$.query.ref.child(fromCol.$key).child('tasks').set(arrItemToRemove);
}
},
};
this.todos.forEach(child => {
if (lowestOrder > child.order) lowestOrder = child.order;
if (highestOrder < child.order) highestOrder = child.order;
// console.log(child.id);
var selector = this.shadowRoot.querySelector('#myid' + child.id);
Sortable.create(selector, options);
});
console.log('lowestOrder=' + lowestOrder + ' highestOrder=' + highestOrder);
this.set('order', highestOrder);
}
});
}
Ok ... this is what I did to resolve the issue
firebase query is async so I used observer function to update the dummy variable which is used in dom-template. I used async to do that.
The real issue was when you remove element from list that sortablejs has used to render the items. By use of Dummy variable that is copy of firebase object I was able to avoid this issue.
I offline sync the object when user leaves the page. It works fine now.

uibootstrap : change modal header background color

I am using ui bootstrap in my Angularjs application.
I want to customize the modals header by changing the backgroud color.
But if I zoom on the header of a modal, I see that the header where I can apply the color changes is not round as it should be.
So the result is not nice in the end.
How can I change the header background color in a "nice" way?
Thank you.
[UPDATE]
onEnter: ['$stateParams', '$state', '$uibModal', function($stateParams, $state, $uibModal) {
$uibModal.open({
templateUrl: 'app/entities/consultant/consultant-dialog.html',
controller: 'ConsultantDialogController',
controllerAs: 'vm',
backdrop: 'static',
windowClass: 'consultant-dialog-modal-window',
HTML CODE OF MODAL :
<form name="editForm" class="form-horizontal" role="form" novalidate ng-submit="vm.save()" show-validation>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"
ng-click="vm.clear()">×</button>
<h4 class="modal-title" id="myConsultantLabel">modal header</h4>
</div>
<div class="modal-body">
Just set the CSS overflow property on modal-content to hidden:
.modal-content {
overflow: hidden;
}
See snippet for details.
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $uibModal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.animationsEnabled = true;
$scope.open = function (size) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$scope.toggleAnimation = function () {
$scope.animationsEnabled = !$scope.animationsEnabled;
};
});
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $uibModal service used above.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $uibModalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$uibModalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
});
.modal-content {
overflow: hidden;
}
.modal-header {
background: lightblue;
}
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.1.0.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
{{ item }}
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
</script>
<button type="button" class="btn btn-default" ng-click="open()">Open me!</button>
<button type="button" class="btn btn-default" ng-click="open('lg')">Large modal</button>
<button type="button" class="btn btn-default" ng-click="open('sm')">Small modal</button>
<button type="button" class="btn btn-default" ng-click="toggleAnimation()">Toggle Animation ({{ animationsEnabled }})</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
</body>
</html>
If your build process lets you run less, then this is how I solved it:
// path to your bootstrap source
#import (reference) "../../../bower_components/bootstrap/less/mixins.less";
// remove the background color from the container
.modal-default .modal-content,
.modal-primary .modal-content,
.modal-success .modal-content,
.modal-info .modal-content,
.modal-warning .modal-content,
.modal-danger .modal-content {
background-color: transparent;
}
// apply the border radius to the top and bottom
.modal-default .modal-header,
.modal-primary .modal-header,
.modal-success .modal-header,
.modal-info .modal-header,
.modal-warning .modal-header,
.modal-danger .modal-header {
.border-top-radius(#border-radius-large);
}
.modal-default .modal-footer,
.modal-primary .modal-footer,
.modal-success .modal-footer,
.modal-info .modal-footer,
.modal-warning .modal-footer,
.modal-danger .modal-footer {
.border-bottom-radius(#border-radius-large);
}
.modal-default .modal-body,
.modal-primary .modal-body,
.modal-success .modal-body,
.modal-info .modal-body,
.modal-warning .modal-body,
.modal-danger .modal-body {
background-color: #modal-content-bg;
}
.modal-variant(#color; #background; #border) {
.modal-header {
color: #color;
background-color: #background;
border-color: #border;
}
.modal-footer {
color: #color;
background-color: #background;
border-color: #border;
}
}
// build modals based on button defaults
.modal-default {
.modal-variant(#btn-default-color; #btn-default-bg; #btn-default-border);
}
.modal-primary {
.modal-variant(#btn-primary-color; #btn-primary-bg; #btn-primary-border);
}
// Success appears as green
.modal-success {
.modal-variant(#btn-success-color; #btn-success-bg; #btn-success-border);
}
// Info appears as blue-green
.modal-info {
.modal-variant(#btn-info-color; #btn-info-bg; #btn-info-border);
}
// Warning appears as orange
.modal-warning {
.modal-variant(#btn-warning-color; #btn-warning-bg; #btn-warning-border);
}
// Danger and error appear as red
.modal-danger {
.modal-variant(#btn-danger-color; #btn-danger-bg; #btn-danger-border);
}
(I believe I'm also #importing the base bootstrap.less file)
Then, you can use the usual $uibModal.open(...), or add a property such as windowClass: 'modal-danger'. This adds the class to the underlying container and cascades the change without altering how "normal" modals are styled.
This will color both the modal-header and modal-footer with the standard bootstrap button colors. You can drop the footer declaration in the variant method (and copy the modal-body block) if you'd like to have the footer remain white.