I am working in Angular and I have a following situation:
my.service.ts has this class:
export class MyClass {
MyList: string[] = [];
MyString: string = '';
createString(): void {
this.MyList.forEach(s => {
this.MyString += s + ', ';
});
}
}
And my.component.ts calls it like this:
myData: MyClass[] = [];
this.myService.getMyData().subscribe(res => {
myData = res;
if (myData.length > 0) {
this.myData.forEach(x => x.createString());
}
});
VS Code recognizes the createString function as a metod of MyClass, but I still get an error:
ERROR TypeError: x.createString is not a function
Any explanations?
EDIT: The data comes from back end, and the back end model doesn't have this method. Maybe that is the issue?
The object coming from the server will be just a simple object not an instance of the class MyClass. You can create instances of MyClass and assign the values from the server object to the instance of the class:
this.myService.getMyData().subscribe(res => {
myData = res.map(o => Object.assign(new MyClass(), o));
if (myData.length > 0) {
this.myData.forEach(x => x.createString());
}
});
Accepted soulution didn't help me, so I propose mine. It does not require .map().
My http service:
getOffers() {
return this.http.get('https://ohipo.pl/assets/oferty.json');
}
Consuming service in component:
offers: Offer[] = [];
this.offersService.getOffers().subscribe((response: Offer[]) => {
for (let i in response) {
this.offers[i] = Object.assign(new Offer(), response[i]);
}
Related
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()
}
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!
Task: I want to create a dynamic class by a given JSON Object in ES6.
After a lot of reading in the MDN web docs and much stackoverflow questions i'm totally confused how to get this work.
JSON Object
{
constructor: {
name: "someName",
},
getter: {
function1: () => "someOutput",
function2: () => false,
}
}
While I tried to solve the problem I figured out how to create dynamic getter methods by using "Proxy" or "defineProperty" but how i should handle the constructor?? :(
I hope someone can help me with a hint or an example.
Thanks in advance
You can add constructor to your class created by Proxy using Proxy's "construct" handler method:
const jsonObj = {
constructor: {
name: "someName",
},
getter: {
function1: () => "someOutput",
function2: () => false,
}
}
function baseClass(obj) {
for(i in obj){
this[i] = obj[i]
}
}
const handler = {
construct(target, args) {
return new target(jsonObj.constructor);
}
};
const NewClass = new Proxy(baseClass, handler);
I was trying out the 5 min Anuglar2 Tutorial and when it said that you are able to use external templates I tried it.
My component looks like this
import {Component, Template, bootstrap} from 'angular2/angular2';
// Annotation section
#Component({
selector: 'my-app'
})
#Template({
url: "component.html"
})
// Component controller
class MyAppComponent {
constructor() {
this.name = 'Alice';
}
}
bootstrap(MyAppComponent);
I had a mistake in my external template and fixed it, but the HTML file was still cached so I couldn't the effects in the browser.
Figuring out how they cache it I looked at the code on Github
I found this
#angular/modules/angular2/src/core/compiler/template_loader.js
#Injectable()
export class TemplateLoader {
_xhr: XHR;
_htmlCache: StringMap;
_baseUrls: Map<Type, string>;
_urlCache: Map<Type, string>;
_urlResolver: UrlResolver;
constructor(xhr: XHR, urlResolver: UrlResolver) {
this._xhr = xhr;
this._urlResolver = urlResolver;
this._htmlCache = StringMapWrapper.create();
this._baseUrls = MapWrapper.create();
this._urlCache = MapWrapper.create();
}
// TODO(vicb): union type: return an Element or a Promise<Element>
load(template: Template) {
if (isPresent(template.inline)) {
return DOM.createTemplate(template.inline);
}
if (isPresent(template.url)) {
var url = this.getTemplateUrl(template);
var promise = StringMapWrapper.get(this._htmlCache, url);
if (isBlank(promise)) {
promise = this._xhr.get(url).then(function (html) {
var template = DOM.createTemplate(html);
return template;
});
StringMapWrapper.set(this._htmlCache, url, promise);
}
return promise;
}
So I check out the StringMapWrapper angular/modules/angular2/src/facade/collection.es6
and for set the code is just
static set(map, key, value) {
map[key] = value;
}
I saw that the StringMapWrapper comes from global
export var StringMap = global.Object;
But looking in angular/modules/angular2/src/facade/lang.es6 I cant figure out where the Map is cached.
I do not know much about the caching process and hope someone could explain how they do it in this case.
StringMapWrapper.create() creates an object literal {}. They use something like StringMapWrapper for Dart support where these primitives are created differently in the other language. In short all they're doing is this
var cache = {};
xhr(templateUrl).then(template => {
cache[templateUrl] = template;
return template;
})
#gdi2290 had nearly answered your question, and if you want to understand more about Cache Management in JavaScript/TypeScript, please see my post here http://www.ravinderpayal.com/blogs/12Jan2017-Ajax-Cache-Mangement-Angular2-Service.html .
There is a step by step explanation of a cache management class which acts as Layer to AJAX, and can be injected to components as Service. Here's a synopsis of code from class:-
private loadPostCache(link:string){
if(!this.loading[link]){
this.loading[link]=true;
this.links[link].forEach(a=>this.dataObserver[a].next(false));
this.http.get(link)
.map(this.setValue)
.catch(this.handleError).subscribe(
values => {
this.data[link] = values;
delete this.loading[link];
this.links[link].forEach(a=>this.dataObserver[a].next(false));
},
error => {
delete this.loading[link];
}
);
}
}
private setValue(res: Response) {
return res.json() || { };
}
private handleError (error: Response | any) {
// In a real world app, we might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
postCache(link:string): Observable<Object>{
return Observable.create(observer=> {
if(this.data.hasOwnProperty(link)){
observer.next(this.data[link]);
}
else{
let _observable=Observable.create(_observer=>{
this.counter=this.counter+1;
this.dataObserver[this.counter]=_observer;
this.links.hasOwnProperty(link)?this.links[link].push(this.counter):(this.links[link]=[this.counter]);
_observer.next(false);
});
this.loadPostCache(link);
_observable.subscribe(status=>{
if(status){
observer.next(this.data[link]);
}
}
);
}
});
}
I'm trying to Proxy an inheritance structure from within a node module and allow the client to instantiate a new Class A. Currently when trying to access class B's parent methods I get a.parentMethod is not a function
handler.js ->
module.exports = {
get(target, key, receiver) {
return target.getAttribute(key)
},
set(target, key, value, receiver) {
return target.setAttribute(key, value)
}
}
A.js ->
const handler = require('handler')
class B {
constructor(data) {
this.data = data
}
parentMethod() {
... do stuff
}
}
class A extends B {
constructor(data){
super(data)
}
}
module.exports = function(data) {
return new Proxy(new A(data), handler)
}
////
const A = require('A')
var a = new A
a.parentMethod()
Where am I going wrong with this structure? I'm new to Proxy!
Thanks
EDIT -
Further context:
I'm trying to keep sets of properties in sync based on a valueSchema I have defined. When I set Artwork.title I need Artwork['Artwork Title'] to be updated with the same value. Likewise when I retrieve Artwork.title I get the value of Artwork['Artwork Title']. Hopefully this helps a bit. I'm stuck at the above error so I can't be sure what I've written actually works yet! I'm trying to debug why the function can't be found first...
class Instance {
constructor(data) {
this._valueAttributes = {}
}
setAttribute(key, value) {
if (this._isValueAttribute(key)) {
return this._getSetValueAttribute(key, value)
}
throw Error('Cannot set invalid property '+key+' on instance.')
}
getAttribute(key) {
if (this._isValueAttribute(key)) {
return this._getSetValueAttribute(key)
}
}
_getSetValueAttribute(key, value) {
let schemaKey = this._getSchemaKey(key)
if (_.isFunction(schemaKey)) {
return alias(data)
}
if (value === undefined) {
return this._valueAttributes[schemaKey]
}
return this._valueAttributes[schemaKey] = value
}
_isValueAttribute(key) {
return _.keys(this._valueSchema).indexOf(key) === -1
}
}
class Artwork extends Instance {
constructor() {
this._valueSchema = {
medium: 'Artwork Medium',
title: 'Artwork Title'
}
}
}
///
a = new Artwork
a.title = 'thing'
a['Artwork Medium'] = 'medium';
I need
a.title == a['Artwork Title']
a['Artwork Medium'] == a.medium
It's very likely I've royally screwed it all up. I've assumed that I can access __valueSchema on the child from the parent. Is this not possible?