error - function is not the function in child class - javascript

I have a parent class Weather, which shows the weather for 4 days. I have a child class, which gets an array of cities. And he should show the the weather for 4 days for a random city in this array. But I have an error - this.makeRandom(...).then is not a function. What is wrong?
class GetRandomCity extends Weather {
constructor(city) {
super();
this.city = city;
}
makeRandom() {
//code
};
init() {
this.makeRandom().then(city => {
this.getCoordinates(city)
}).then(coords => {
return this.getWeatherForecast(coords);
}).then((forecast) => {
const { currently, daily } = forecast;
this.renderForecastInfo(currently, daily);
});
}
}
const w1 = new GetRandomCity(['Paris', 'Minsk', 'Madrid', 'Chikago']);

The reason is because makeRandom does not return a promise. You need to put a return statement before getCoordinates if you choose to make it an async function. Else, you could change your code in your init function to this and it should work:
const city = this.makeRandom();
this.getCoordinates(city).then(coords => {
return this.getWeatherForecast(coords);
}).then(forecast => {
const { currently, daily } = forecast;
this.renderForecastInfo(currently, daily);
});

Related

Setting a variable equal to a return of function

I'm trying to set a variable equal to a return of a function but I don't understand how can i do.
In particular this is the code:
constructor() {
super();
this.manager = new BleManager()
this.state = {
info: "",
values: {}
}
this.deviceprefix = "FM_RAW";
this.devicesuffix_dx = "DX";
}
model_dx(model) {
return this.deviceprefix + model + this.devicesuffix_dx
}
if (device.name === "THERE i should use the return of model_dx") {
this.info(device.id)
this.manager.stopDeviceScan();
device.connect()
I should check device.name with the result of the model_dx function. How can I do?
Thank you
How about calling it? Create a instance of the object and call it:
// Assume the name is CustomObj
class CustomObj {
constructor() {
super();
this.manager = new BleManager()
this.state = {info: "", values: {}}
this.deviceprefix = "FM_RAW";
this.devicesuffix_dx = "DX";
}
model_dx(model) {
return this.deviceprefix + model + this.devicesuffix_dx
}
}
// I suppose this is outside of the object? Otherwise it would be out of scope anyways as you wrote your if in no function or whatsoever
CustomObj obj = new CustomObj(); //<-- Create instance
let alwaysdifferentParam = "model test";
if (device.name === obj.model_dx(alwaysdifferentParam )) { //<-- Call it
this.info(device.id)
this.manager.stopDeviceScan();
device.connect()
}
Try this:
if (device.name === this.model_dx('pass the desired value here')) {
this.info(device.id)
this.manager.stopDeviceScan();
device.connect()
}

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!

unable to select all checkboxes in tree using angular2-tree on init

Objective : i have a button named "feed data" so when ever i click it the data will be loaded i mean the tree with checkboxes here my requirement is when ever i click it along with data all the check boxes have to be checked on init i tried using
this.treeComp.treeModel.doForAll((node: TreeNode) => node.setIsSelected(true));
but it is not working below is my code
click(tree: TreeModel) {
this.arrayData = [];
let result: any = {};
let rs = [];
console.log(tree.selectedLeafNodeIds);
Object.keys(tree.selectedLeafNodeIds).forEach(x => {
let node: TreeNode = tree.getNodeById(x);
// console.log(node);
if (node.isSelected) {
if (node.parent.data.name) //if the node has parent
{
rs.push(node.parent.data.name + '.' + node.data.name);
if (!result[node.parent.data.name]) //If the parent is not in the object
result[node.parent.data.name] = {} //create
result[node.parent.data.name][node.data.name] = true;
}
else {
if (!result[node.data.name]) //If the node is not in the object
result[node.data.name] = {} //create
rs.push(node.data.name);
}
}
})
this.arrayData = rs;
tree.selectedLeafNodeIds = {};
}
selectAllNodes() {
this.treeComp.treeModel.doForAll((node: TreeNode) => node.setIsSelected(true));
// firstNode.setIsSelected(true);
}
onTreeLoad(){
console.log('tree');
}
feedData() {
const results = Object.keys(this.data.info).map(k => ({
name: k,
children: this.data.info[k].properties
? Object.keys(this.data.info[k].properties).map(kk => ({ name: kk }))
: []
}));
this.nodes = results;
}
feedAnother() {
const results = Object.keys(this.dataa.info).map(k => ({
name: k,
children: this.dataa.info[k].properties
? Object.keys(this.dataa.info[k].properties).map(kk => ({ name: kk }))
: []
}));
this.nodes = results;
}
onActivate(event) {
this.selectedDataList.push(event.node.data);
console.log(this.selectedDataList)
}
onDeactivate(event) {
const index = this.selectedDataList.indexOf(event.node.data);
this.selectedDataList.splice(index, 1);
console.log(this.selectedDataList)
}
below is my stackblitz https://stackblitz.com/edit/angular-hrbppy
Use updatedata and initialized event to update the tree view to check all checkboxes.
app.component.html
<tree-root #tree *ngIf ="nodes" [nodes]="nodes" [options]="options" [focused]="true"
(initialized)="onTreeLoad()"
(updateData)="updateData()"
(select)="onActivate($event)"
(deselect)="onDeactivate($event)">
</tree-root>
It'll initiate tree-root component only if nodes variable is available,
then in the initialized and updateData event call selectAllNodes method to select all checkboxes.
app.component.ts
updateData() {
this.selectAllNodes();
}
onTreeLoad(){
this.selectAllNodes();
}
Refer to this slackblitz for working example.
just, in your function feed data call to your function this.selectAllNodes() enclosed in a setTimeout. You can see your forked stackblitz
setTimeout(()=>{
this.selectAllNodes()
})
NOTE: I see in your code you try to control in diferents ways the items selected. I simplified using a recursive function.
In this.treeComp.treeModel.selectedLeafNodeIds we have the items that are changed, so
getAllChecked()
{
const itemsChecked=this.getData(
this.treeComp.treeModel.selectedLeafNodeIds,null)
console.log(itemsChecked);
}
getData(nodesChanged,nodes) {
nodes=nodes||this.treeComp.treeModel.nodes
let data: any[] = []
nodes.forEach((node: any) => {
//in nodesChanged we has object like {1200002:true,123132321:false...}
if (nodesChanged[node.id]) //can be not changed, and then it's null because
//it's not in object or can be changed to false
data.push({id:node.id,name:node.name})
//or data.push(node.name); //if only need the "name"
if (node.children)
data=[...data,...this.getData(nodesChanged,node.children)]
}
);
return data
}
Updated I updated the function getData to include the "parent" of the node, but looking the code of #Raghul selvam, his function like me more than mine.
getData(nodesChanged,nodes,prefix) {
nodes=nodes||this.treeComp.treeModel.nodes
let data: any[] = []
nodes.forEach((node: any) => {
if (nodesChanged[node.id])
data.push(prefix?prefix+"."+node.name:node.name)
if (node.children)
data=[...data,...this.getData(nodesChanged,node.children,prefix?prefix+"."+node.name:node.name)]
}
);
return data
}
And call it as
this.getData(this.treeComp.treeModel.selectedLeafNodeIds,null,"")
You could add this in your onTreeLoad function. You could add a boolean flag(treeLoaded) for tracking if the tree has loaded or not.
onTreeLoad(tree){
this.selectAllNodes();
this.treeLoaded = true;
}

how to get the exact search result in angular 4

i have implemented the search module in my app. The search does not search for the exact phrase, but rather individually for each word in the phrase. For example, if you search for "Comprehensive Metabolic", you would only expect to see the CMP Panels, but the search actually returns every single panel that has either the word "Comprehensive" or "Metabolic", which is a much longer list.
any help can i get?
is there any pipe i can use to filter exact search?
here is my search component html
<input #searchInput type="text" (focus)="onFocus($event)" (blur)="onBlur($event)" (keyup)="onKeyUp($event)" placeholder="Search">
its Ts file
#Input() searchTerm: string = "";
#Output() onSearchInputUpdate = new EventEmitter();
#ViewChild("searchInput") searchInputField: ElementRef;
public searchFocus: boolean;
private searchTermTimeoutId;
private waitTime: number = 500; // half a second
onBlur(event) {
// setTimeout so clearSearch click event has time to be called first
setTimeout(() => {
if (event.srcElement.value.length === 0) {
this.searchFocus = false;
}
}, 100);
}
onKeyUp(event) {
if (this.searchTermTimeoutId) {
clearTimeout(this.searchTermTimeoutId);
}
this.searchTermTimeoutId = setTimeout(() => {
this.onSearchInputUpdate.emit(this.searchInputField.nativeElement.value);
}, this.waitTime);
}
i added this in my component where i am using it
here parent component's html
<app-search-list (onSearchInputUpdate)="onSearchFieldUpdate($event)">
</app-search-list>
<app-test-selection-category-list
(onCategorySelect)="updateTestPanelView($event)"></app-test-selection-
category-list>
its Ts File
onSearchFieldUpdate($event) {
this.searchField = $event;
this.updateTestPanelView(this.selectedCategoryId);
}
updateTestPanelView(categoryId: string) {
this.selectedCategoryId = categoryId;
switch (this.selectedCategoryId) {
case '-1':
this.fetchAllTests();
break;
case "0":
this.fetchFavoritesForCategories();
break;
default:
this.fetchTestsForCategory();
}
}
fetchAllTests() {
this.testOrderService.getAllTests(this.searchField).subscribe(response =>
{
const {panels, tests} = this.extractPanelsAndTests(response);
this.testSelectionSession = {
...this.testSelectionSession,
PanelsForAll: panels,
IndividualTestPanelsForAll: tests
};
this.store.dispatch(
new SetTestOrderTestSelectionSession(this.testSelectionSession)
);
})
}
fetchFavoritesForCategories() {
this.testOrderService
.getAllFavorites(this.searchField)
.subscribe(favorites => {
this.testSelectionSession = Object.assign(
{},
this.testSelectionSession,
{
FavoritesByCategory: _.groupBy(favorites, 'CategoryName')
}
);
this.store.dispatch(
new SetTestOrderTestSelectionSession(this.testSelectionSession)
);
});
}
fetchTestsForCategory() {
this.testOrderService
.getTestsByCategoryId(this.selectedCategoryId, this.searchField)
.subscribe(categoryResponse => {
const {panels, tests} = this.extractPanelsAndTests(categoryResponse);
this.testSelectionSession = Object.assign(
{},
this.testSelectionSession,
{
PanelsForCategory: panels.map(panel => {
panel.CategoryId = this.selectedCategoryId;
return panel;
}),
IndividualTestPanelsForCategory: tests.map(
test => {
test.CategoryId = this.selectedCategoryId;
return test;
}
)
}
);
this.store.dispatch(
new SetTestOrderTestSelectionSession(this.testSelectionSession)
);
});
}
i am getting every result which has either Comprehensive or metabolic.
like this
what can i do to get exact result
any help?
Thanks

Reload HTML elements with javascript not working

I get a list of items and use it to dynamically create an HTML list
_loadList(){
HttpUtils.get('http://myserver/list/users/')
.then((res) => {
const self = this;
res.forEach((item) => {
userListContainer.append('<li> item.name </li>')
});
});
}
I call this function in the constructor, everything is working fine
constructor() {
this._loadList();
}
I am trying to recall this function every 5 seconds to update the list with the new result:
constructor() {
const that = this;
this._loadList();
window.setInterval(function(){
that._loadList();
}, 5000);
}
The function is called, the received result contains the new content, but the HTML is not updated. Do you have an idea about the problem?
You can try below code that will work for in your case. You can checkout https://es6console.com/jgyxgm1f/ example which will alert random number (in your case it's equivalent of adding new data coming from API response).
_loadList = () => {
HttpUtils.get('http://myserver/list/users/')
.then((res) => {
userListContainer.empty();
res.forEach((item) => {
userListContainer.append('<li> item.name </li>')
});
});
}
constructor = () => {
this._loadList();
window.setInterval(() => {
this._loadList();
}, 5000);
}

Categories