I have a project which contains a global VueJS file with child vuejs file depending on what page you are on.
I am trying to work out how to create a media manager which I can call multiple times per page and have it open up with a modal where I can either select an image or upload an image. I already know how to upload an image. What i need is once an image is selected or uploaded and a "Select" button is pressed it will close the modal and return an array back to the original element that called it and assigns to that element's variable.
Example would be:
I have a vuejs element called article_image with a variable called "article_image_data" and contains a button. When the button is created it opens the modal manager which you will need to select the image you want and press "Select" this modal then closes and returns an array which will be assigned to "article_image_data" and on the same page there may be a "category" section as well.
To make it simple, in your modal manager, listen to the change event on your file input.
<!-- ModalManager.vue -->
<template>
<div class="modal">
<input type="file" #change="$emit('selectedFiles', $event.target.files)">
</div>
</template>
Then from your parent who implemented the modal manager, you can get the file list on the selectedFiles event.
<!-- ArticleImage.vue -->
<template>
<ModalManager
#selectedFiles="onSelectedFiles"
v-if="modalOpen">
</template>
Easy now to deal with a FileList
export default {
components: {
ModalManager
}
data () {
return {
modalOpen: false,
articleImageData: null,
}
},
methods: {
onSelectedFiles (fileList) {
console.log('Received a FileList from ModalManager', fileList)
}
}
}
If you need a deeper component management for your modals, you either propagate your events from bottom to top with something like this:
<element #childEvent="$emit('childEvent')">
But the idea stays the same
Related
I have two components that display on one page (first is 70% of the page, the other 30%). One in which the map is and another where I want to show the panel (info on how to get to the destination: turn left, then right, etc.)
I used agm-directions to get the panel - https://robby570.tw/Agm-Direction-Docs/source/featured/direction.html (look at Update Panel With New Query ).
I managed to create it well and, when you click a button the panel will appear with the text, but on the map component, under the map (see picture 2). This is because I put <div #myPanel></div> under the map in the first component.
I want to get that panel text on the second component. I do not know how to do this because I bind the panel in the map component [panel]="myPanel", according to the documentation above.
So is there a way I can transfer that bonded data in a different component ?
Here is the first component html:
<agm-map [zoom]="zoom" [latitude]="lat" [longitude]="lng">
...
<agm-direction
[origin]="origin"
[destination]="destination"
[travelMode]="transitOptions"
[visible]="show"
[renderOptions]="renderOptions"
[markerOptions]="markerOptions"
[panel]="myPanel" <!-- THIS IS IMPORTANT FOR INFO -->
>
</agm-direction>
...
</agm-map>
<div #myPanel></div>
The second component is just some generic html.
TLDR: How can I get <div #myPanel></div> to work in a different component when I bind [panel]="myPanel" in agm-direction.
Managed to get the value thanks to
#ViewChild("myPanel", {static: false}) myPanel;
Then, in a function that activates when the button is clicked:
let _this = this;
setTimeout(function() {
console.log(_this.myPanel);
if(_this.myPanel != undefined){
let ivan = _this.myPanel;
console.log("test myPath", ivan);
//console.log("Test", JSON.stringify(this.myPanel.nativeElement.innerHTML));
console.log(_this.myPanel.nativeElement.innerHTML); //THIS IS THE ANSWER
}
}, 500);
So the image above is my code inside a comp.js (Vue component) when the user clicks 'Update' button, it will grab the updated input and push it to firestore.
I put v-on:emit on every single input and I tried to reference it on the 'Update' button.
This is my modal inside the HTML file, I tried to connect the function from comp.js to function.js.
However, the methods above didn't work and it gave me the error below.
I'm not really sure how to grab the value from each input and connect
UPDATED CODE BASED ON ITTUS'S SUGGESTION:
So based on the Ittuss suggestion below, I tried to pass over to items through the emit inside the Update button, I did this because I want to pass all the input values above the button to update the Firestore database.
I changed the cuisedit to this:
And I updated the function in the .js to this:
However, I received an error saying that I didn't reference correctly.
Do you know why it isn't grabbing the value emitted from the button?
In your cuiseedit component, $emit should contain only 1 additional parameter:
<button #click="$emit('some-change', obj2.id)"></button>
and in component:
<transition name="fade">
<cuisedit v-if="showModal" :obj2="cuisinemodal" #some-change="updateData">
</cuisedit>
</transition>
updateData: function (id) {
firestore.collection("koreanbap-cuisines").doc(id).update()....
}
Note
If you want to pass more data, you should wrap them to an object
<button #click="$emit('some-change', {id: obj2.id, event: $event})"></button>
Currently, I'm trying to add dynamic tabs which have child component, Within the child component, there are several ngx-smart-modal models. I'm able to create dynamic tabs with a close button on it. The issue arises when there are more than one tabs.
Issue
Instance 1: I'm on the first dynamically created tab and I try to click on the model present in a custom component, Model pops up in the last tab of the dynamically created tab. (With the last component details and not desired component details)
Instance 2: If it has only a single dynamically created a model then it works perfectly fine.
Code
HTML
<p-tabPanel [header]="doc.docName" leftIcon="ui-icon-web-asset" *ngFor="let doc of docProps; let i = index" [selected]="true" (onClose)="closeDocProps(doc)" [closable]="true">
<app-child-component [docId]="doc.docId" ></app-child-component>
</p-tabPanel>
app-child-component has several models present in it.
app-child-component (HTML)
<ngx-smart-modal #myModal identifier="myModal">
<h1>Title</h1>
<p>Some stuff...</p>
<button (click)="myModal.close()">Close</button>
</ngx-smart-modal>
TS (Parent component)
on document click operation in the parent component
this.docProps.push({
docId: document.id,
docName : document.docTitle
});
this.changeDetectorRef.detectChanges();
this.activeIndexNumber = this.docProps.length; // to open up the last tab clicked.
also, I'm changing the tab index number with the change of the tab.
onTabChange(event) {
this.changeDetectorRef.detectChanges();
this.activeIndexNumber = event.index;
}
Is there something that I'm doing wrong? Suggestions are highly welcomed.
stackblitz:
https://stackblitz.com/edit/angular-uy3kf5
I'm working on a project about a list of doctors and I'm using polymer 1.0.
For the doctor-list I use a vaadin-grid called doctors-grid.html where I'm getting the data from a JSON. When a doctor is double clicked, a modal dialog opens with the information about the selected doctor.
The content of the dialog is a separate component called doctor-details.html.
The information about the doctor is written in disabled paper-input fields.
I have a modify button in this dialog. When I click on this button, the text of the button changes to "Save".
Now to my problem: Now I also want to enable these disabled paper-input fields when I click on the modify button, so I could change the information about the doctor. After I changed it I want to save the modified data back to the JSON and change the button again to "Modify" and disable all input-fields again.
This is a part of my doctor-details.html
<link rel="import" href="../../bower_components/paper-input/paper-input.html"/>
<link rel="import" href="../../bower_components/paper-input/paper-textarea.html"/>
<dom-module id="doctor-details">
<template>
<table>
<tr>
<td>Name</td>
<td><paper-input label="{{doctordata.name}}" disabled></paper-input></td>
</tr>
<tr>
<td>Forename</td>
<td><paper-input label="{{doctordata.forename}}" disabled></paper-input></td>
</tr>
</table>
</template>
<script>
Polymer({
is: 'doctor-details',
properties: {
doctordata: {
type: Object,
value: null
}
</script>
</dom-module>
This is from the doctors-grid.html, where I click the button and the paper-inputs from the doctor-details.html should be enabled, so I can modify them. And in this function i also should enable these inputfields.
onClick: function() {
var button = this.$.msbutton;
button.textContent = 'Save';
var inputfields = [];
//How can I save all paper-inputs in this array?
//How can I enable all paper-inputs?
}
I don't post the whole code directly here, because I think it's easier when you look at the whole project (and it would be too much code).
So I have a link to my dropbox: https://www.dropbox.com/s/crsrixs0nw6tvyy/WebContentEN.zip?dl=0
I googled and tried myself, but I always failed. I'm a beginner in polymer, so i would really appreciate it if someone can help me, because I really have no idea how to do this. Thanks!
How can I save all paper-inputs in this array?
It's not a good idea to directly retrieve input fields from grid elements. You can control the disabled property with binding. On the inside you create a property in doctor-details and bind it to inputs.
<paper-input label="{{doctordata.name}}"
disabled="{{disabled}}></paper-input>
<script>
Polymer({
is: 'doctor-details',
properties: { disabled: Boolean }
});
</script>
On the outside add the same property and bind with each doctor-details.
<doctor-details disabled="{{editDisabled}}></doctor-details>
<script>
Polymer({
is: 'doctor-grid',
properties: {
editDisabled: {
value: true
}
},
onClick: function() {
this.editDisabled = !this.editDisabled;
}
});
</script>
How can I enable all paper-inputs?
To sum up, you control all input through a single boolean property bound to your elements.
Also, I'd rather have two buttons to hide/show depending on editDisabled rather than change the title of a single button.
As a practical exercise in learning bare-bones JS programming in depth (on up to date browsers), I am building an SPA to maintain customer records. The only external library I am using is Mithril.js MVC. So far I have got a table view with live data from my database, which includes edit, merge and delete buttons for each record. The editing is done and working well, using an inline "form" and save/cancel for that works.
I am now trying to implement delete and merge, both of which need a popup confirmation before being actioned, which is where I am stuck. I know exactly what I'd do in a desktop GUI environment, so the roadblock may be my lack of understanding of the browser front-end more than of Mithril, per se.
Ideally, I'd like to create a self-contained, reusable "popup" component represent the popup, but I can't see how I should go about doing this in JS using Mithril, in particular, but not solely, how to make Mithril to overlay one view on top of another.
Any assistance would be appreciated, from a broad outline to specific code snippets.
You probably want to use a view model flag to control the modal popup's visibility.
//modal module
var modal = {}
modal.visible = m.prop(false)
modal.view = function(body) {
return modal.visible() ? m(".modal", body()) : ""
}
//in your other view
var myOtherView = function() {
//this button sets the flag to true
m("button[type=button]", {onclick: modal.visible.bind(this, true)}, "Show modal"),
//include the modal anywhere it makes sense to
//its visibility is taken care by the modal itself
//positioning is controlled via CSS
modal.view(function() {
return m("p, "modal content goes here")
})
}
To make a modal dialog, you can either use the styles from one of the many CSS frameworks out there (e.g. Bootstrap), or style .modal with your own CSS
/*really contrived example to get you started*/
.modal {
background:#fff;
border:1px solid #eee;
position:fixed;
top:10px;
left:100px;
width:600px;
}
I don't know if I am just not quite getting MVC, but I simply set a view-model object that contains the detail of the popup, and then when generating the view if that is currently set I populate the div containing the popup. CSS controls the look and positioning.
So basically I am relying of Mithril's top-down re-render approach to conditionally build the view based on current application state -- it works really well and is immanently sensible to me.
I actually used a list of popup confirmation objects, so multiple confirmations can queue up.
In the controller, make a confirmation queue:
function Controller() {
...
this.confirmation =[];
...
}
In the view, create a confirmation view div if there's a confirmation queued, or an empty placeholder otherwise (Mithrils differencing works best if container elements don't appear and disappear from render to render):
function crtView(ctl) {
...
return m("div", [
...
crtConfirmationView(ctl),
...
]);
}
function crtConfirmationView(ctl) {
var cfm=ctl.confirmation[0];
return m("div#popup-confirm",(cfm ? muiConfirm.crtView(ctl,cfm.title,cfm.body,cfm.buttons) : null));
}
Then, whenever a confirmation is needed, just push a confirmation object into the queue and let Mithril's drawing system run and rebuild the view.
function deleteRecord(ctl,evt,row,idx,rcd) {
var cfm={
title : m("span","Delete Customer: "+rcd.ContactName),
body : [
m("p","Do you really want to delete customer "+rcd.CustomerId+" ("+rcd.ContactName+") and all associated appointments and addresses?"),
m("p.warning", "This action cannot be undone. If this is a duplicate customer, it should be merged with the other record."),
],
buttons : deleteButtons,
proceed : "delete",
index : idx,
record : rcd,
};
ctl.confirmation.push(cfm);
}
The confirmation object contains whatever properties that the confirm helper function crtView needs to create a confirmation view and then take action when the user clicks a button (or presses ENTER or ESCAPE, etc) -- just standard UI stuff that you abstract away into shared reusable components.
Note: Just in case anyone has questions about the array index, I have since moved away from using the array index to identify the record in the data model (when the delete is complete the array element should be removed). Instead I locate the affected record using database ID, which is resilient against intervening changes in the model, like sorting the list.