Display datas on modal dialog in angular4 application - javascript

I have a angular 4 application and I want to display datas in dialog. So, I use #Output to pass data from child to parent component.
So, in the parent component I have :
export class DashboardComponent {
myTask;
public returnTask(task: any):void {
console.log("returnTask");
this.myTask = task;
console.log(this.myTask);
}
openDialogEditTask() {
console.log(this.myTask);
let dialogRef = this.dialogEditTask.open(DialogEditTask, {
//task
data: {
start: this.myTask.start,
end: this.myTask.end,
status: this.myTask.status,
user: this.myTask.user,
content: this.myTask.content,
id: this.myTask.id,
rate: this.myTask.rate
}
});
dialogRef.afterClosed().subscribe(result => {
this.selectedOption = result;
});
}
}
In the parent html, I have :
<visTimeline (myTask)="returnTask($event)"></visTimeline>
In the child component, I have :
export class VisTimelineComponent {
#Output() myTask: EventEmitter<any> = new EventEmitter<any>();
}
And I emit the task with self.myTask.emit(task);
So, I get the datas in the parent component (I can see them in the console) but I can't use them in openDialogEditTask because it's undefined.
So, do you know how can I get the datas before calling the function to have the datas in the dialog ?
EDIT :
This is my code to emit datas in child component :
ngOnInit() {
Timeline.prototype.onTaskDoubleClick = function(task) {
console.log("Double click on task " + task.id);
console.log(task);
$('#editTask').click();
self.myTask.emit(task);
};
}
Timeline.prototype.onTaskDoubleClick is a function from a library.

I think you are not able to pass data into you modal component. try with componentInstance method.
openDialogEditTask() {
console.log(this.myTask);
let dialogRef = this.dialogEditTask.open(DialogEditTask, {
height: '90%',
width: '80%'
});
dialogRef.componentInstance.myTaskValue = this.myTask; //<- passing data into DialogEditTask component
dialogRef.afterClosed().subscribe(result => {
this.selectedOption = result;
});
}
in your DialogEditTask declare a variable myTaskValue: any;
you will get all your value you pass into DialogEditTask component in this myTaskValue variable

Related

I can't get my data from my document with firebase

I'm creating a single page application with javascript by using the firebase firestore as database.
I've managed to get all my documents listed where I call for all of them. Each document has an href to the detail page. But on the detailpage, it looks like I don't have any data from my document.
I want to call the title from the document to show as an h1 but noting renders and I don't have any errors in my console..
Anyone who can help me?
My code:
This is to get all the documents (who are events)
// Get events
import firebase from 'firebase/app';
import 'firebase/firestore';
const Events = {
getAll: async () => {
// get firestore
const db = firebase.firestore();
// define query
const query = db.collection('events');
// query snapshot
const querySnapshot = await query.get();
// loop over all documents
return querySnapshot.docs.map((doc) => (
{
...doc.data(),
id: doc.id,
}
));
},
// get the data from a detailpage by the ID
getById: async (id) => {
const db = firebase.firestore();
const event = await (await (db.collection('events').doc(id).get())).data();
return event;
},
};
export default Events;
My component to render all documents as a list
import Component from '../lib/Component';
import Elements from '../lib/Elements';
import Router from '../Router';
import Events from '../lib/Events';
class EventsComponent extends Component {
constructor() {
super({
name: 'events',
model: {
events: [],
},
routerPath: '/events',
});
this.eventsLoaded = false;
}
// Get the events one by one, make them an href to their detail page and show the name of the
event
loadEvents() {
if (!this.eventsLoaded) {
Events.getAll().then((data) => {
this.model.events = data.map((event) => ({
href: `${Router.getRouter().link('/event')}/${event.id}`,
textContent: event.title,
}));
});
this.eventsLoaded = true;
}
}
render() {
const { events } = this.model;
// create home container
const eventsContainer = document.createElement('div');
// Load events
this.loadEvents();
// Check if there are any events
if (events.length === 0) {
eventsContainer.innerHTML = 'There are no events planned at the moment';
} else {
eventsContainer.appendChild(
Elements.createList({
items: this.model.events,
}),
);
}
return eventsContainer;
}
}
export default EventsComponent;
My detail page
// Event Component
import Component from '../lib/Component';
import Elements from '../lib/Elements';
import Events from '../lib/Events';
class EventComponent extends Component {
constructor() {
super({
name: 'event',
model: {
event: [],
},
routerPath: '/event/:id',
});
this.eventLoaded = false;
}
// Set the model loading to true when the id page is founded
loadEvent(id) {
if (!this.eventLoaded) {
this.eventLoaded = true;
Events.getById(id).then((data) => {
this.model.event = data;
});
}
}
render() {
const { event } = this.model;
// create event overview container
const eventContainer = document.createElement('div');
// Check for existing events and return the events.
// Create an h1 with the name of the event as title
if (!event) {
this.loadEvent(this.props.id);
} else {
eventContainer.appendChild(
Elements.createHeader({
textContent: event.title,
}),
);
console.log(this.model.event);
}
return eventContainer;
}
}
export default EventComponent;
You have model set as an array insted of an object in you detail page.
constructor() {
super({
name: 'event',
model: {
event: [],
},
routerPath: '/event/:id',
});
this.eventLoaded = false;
}
When you try to access your event you are trying to get .title from an array insted of an object.
Elements.createHeader({
textContent: event.title,
}),
I would map the event field by field { "field" : 0, "field2": ""} but you may find a way to make it less verbose

Reusable object-literals

I have some component with a table which has actions buttons. When clicking on the button, the component emits an action, for example: (edit, delete,route)
getEvent(action: ActionButtons, object: any) {
// type: (edit,delete,route), route: info where to redirect
const {type, route} = action;
this.action.emit({ type, route, body: object });
}
In the parent component I catch this object by the following function and do some logic depending on the action:
getAction({type, route, body: {...faculty }}) {
const action = {
edit: () => {
this.openFacultyModal(faculty);
},
delete: () => {
this.openConfirmDialog(faculty);
},
route: () => {
this.redirecTo(faculty.faculty_id);
}
};
action[type]();
}
The poblem is, if I want to use the table in another component I have to cut and paste getAction() and just change the function inside object.
It turns out that there will be code duplication.
Is it possible to somehow solve the problem of code duplication using closures or creating a separate class?
You can make your action map object reusable:
const actions = {
edit(target, faculty) {
target.openFacultyModal(faculty);
},
delete(target, faculty) {
target.openConfirmDialog(faculty);
},
route(target, faculty) {
target.redirecTo(faculty.faculty_id);
}
};
Then use it where necessary, for instance in getAction:
getAction({type, route, body: {...faculty }}) {
actions[type](this, faculty);
}

Call a class method from a another class in JavaScript?

I am doing a task where I need to wire up a search field to a simple JS application that displays a few items and the user can search through and filter them.
There are three classes - App, ProductsPanel and Search. Both Search and ProductsPanel are being initialised inside the App class.
The ProductsPanel class holds an array with 10 products.
I want to call a method of ProductsPanel from inside Search that filters through the products. How can I do that?
I've tried using this.productsPanel = new productsPanel() inside the constructor of the first class, but that brings up a new instance which doesn't have the array of all of the products.
Here's the App class:
class App {
constructor() {
this.modules = {
search: {
type: Search,
instance: null
},
filter: {
type: Filter,
instance: null
},
productsPanel: {
type: ProductsPanel,
instance: null
},
shoppingCart: {
type: ShoppingCart,
instance: null
}
};
}
init() {
const placeholders = document.querySelectorAll("#root [data-module]");
for (let i = 0; i < placeholders.length; i++) {
const root = placeholders[i];
const id = root.dataset.module;
const module = this.modules[id];
if (module.instance) {
throw new Error(`module ${id} has already been started`);
}
module.instance = new module.type(root);
module.instance.init();
// console.info(`${id} is running...`);
}
}
}
app = new App();
app.init();
And here are the Search:
export default class Search {
constructor(root) {
this.input = root.querySelector("#search-input");
}
// addEventListener is an anonymous function that encapsulates code that sends paramaters to handleSearch() which actually handles the event
init() {
this.input.addEventListener("input", () => {
this.handleSearch();
});
}
handleSearch() {
const query = this.input.value;
app.modules.productsPanel.instance.performSearch(query);
}
}
And ProductsPanel classes:
export default class ProductsPanel {
constructor(root) {
this.view = new ProductsPanelView(root, this);
this.products = [];
}
init() {
this.products = new ProductsService().products;
this.products.forEach(x => this.view.addProduct(x));
}
performSearch(query) {
query = query.toLowerCase();
this.products.forEach(p => {
if (query === p.name) {
this.view.showProduct(p.id);
} else {
this.view.hideProduct(p.id);
}
});
}
addToCart(id) {
const product = this.products.filter(p => p.id === id)[0];
if (product) {
app.modules.shoppingCart.instance.addProduct(product);
}
}
}
I want to call ProductsPanel's performSearch method but on the instance created by the App class. I have no clue on how I can do that.
Try below custom event handler class
class CustomEventEmitter {
constructor() {
this.eventsObj = {};
}
emit(eName, data) {
const event = this.eventsObj[eName];
if( event ) {
event.forEach(fn => {
fn.call(null, data);
});
}
}
subscribe(eName, fn) {
if(!this.eventsObj[eName]) {
this.eventsObj[eName] = [];
}
this.eventsObj[eName].push(fn);
return () => {
this.eventsObj[eName] = this.events[eName].filter(eventFn => fn !== eventFn);
}
}
}
How to use?
create the object of CustomEventEmitter class
let eventEmitter = new CustomEventEmitter()
Subscribe an event
emitter.subscribe('event: do-action', data => {
console.log(data.message);
});
call the event
emitter.emit('event: do-action',{message: 'My Custom Event handling'});
Hope this helps!

How to update data in Vuejs?

I want to display the updated data in the modal. There is a click function which trigger the testing(data) function below.
The data comes out right in the function. However, the template doesn't seem to update, it still displays the previous data. How can I fix this?
Script:
function testing(data) {
const testingLink = new Vue ({
el: '#test',
data: { selected: data },
methods: {
showDialog: function() { $("#test).modal() }
}
})
testingLink.showDialog()
}
You shouldn't create a Vue Instance in a repeatable function
Try it in following way:
const testingLink = new Vue ({
el: '#test',
data: { selected: null },
methods: {
showDialog: function(data) {
this.selected = data
$("#test").modal()
}
}
})
testingLink.showDialog(YOUR_DATA_YOU_WANT_TO_PASS)

How to fetch id from one component to other using angular4

I have 2 components present in one ts file.
TS:
This is present in one component
addSubCategory(boat:Boat):void {
const reff = this.dialog.open(AddSubCategoryDialog, {
data: { }
});
const sub = reff.componentInstance.onBoatSubAdd.subscribe((data) => {
this.boatSubTypes.boat_type_id = boat.id;
this.service
.addSubBoat(data)
.subscribe(
response => {
console.log(response);
this.dialog.closeAll();
this.dialog.open(AddSubCategoryDialog);
this.loadAllBoats();
}, error => {
this.snackBar.open('Failed to add company', 'X' , {
duration: 2000,
});
});
});
}
}
I need to fetch the boat.id present in this file to the below given function
This is present in one more component but within same TS file:
add(boatSubTypes:BoatSubTypes): void {
this.addClicked = true;
this.boatSubTypes.boat_type_id = this.boatSubTypes.boat_type_id;
this.onBoatSubAdd.emit(boatSubTypes);
}
Can anyone help me to solve this.

Categories