typescript getter / setter on array property - arrays

Is there a good way to use getter / setter pattern for array properties?
For example:
export class User {
private _name: string;
set name(value: string) {
this._name = value;
}
get name(): string {
return this._name;
}
private _roles = new Array<string>();
set roles(value: Array<string>) {
this._roles = value;
}
get roles(): Array<string> {
return this._roles;
}
constructor() {
}
}
While changing user.name fires the setter method, adding or removing items from roles does not.
Now i think i understand why it does not fire the setter, because adding items to the array does not change the pointer but merely adds to the already allocated space (correct me if i'm wrong).
How can we get the desired getter / setter behaviour on array properties?

As you said doing something like user.roles.push('my-role') will merely mutate the existing array. Instead of giving direct access to the array through the roles-setter, you could add methods like addRole and removeRole. Then you can implement whatever logic you need when adding or removing to the roles array, keeping it totally private.

Related

how to change value in struct globally in swift

So I have an api request that requests a bunch of data from a fake api url, the data I am getting is being put on a placeholder, I just want to have a global variable to be able to use that array of codable data in my collectionviews.
struct productsList{
static var itemsList = [ProductItem]()
}
func getProducts() {
storeRepo
.getAllProducts()
.subscribe { result in
productsList.itemsList = result
for item in productsList.itemsList{
print(item.category)
}
} onError: { error in
print(error.localizedDescription)
}.disposed(by: disposeBag)
}
func printReuslt() {
for i in productsList.itemsList{
print(i.id)
}
}
note that it's not printing the printResult() but it's looping inside of the .subscribe
note that i am using Moya as well as RXswift
What you're looking for is called a Singleton. Swift makes this extremely easy to do. Basically, the short and sweet is that the struct you create, initializes itself as a property of itself. Anytime you access (In this example) APIHandler.shared you'll get a reference to the only single object, which has your other properties dataObj1 and someObj2 from this example.
class APIHandler {
let shared = APIHandler()
var dataObj1: YourObj?
var someObj2: YourObj2?
init() {
self.someObj1 = yourMethodCall()
self.someObj2 = someCalculation()
}
}
This is how you access it from another class. BE CAREFUL you can access APIHandler.someObj which would result in a null reference exception if you don't have an object created, so when doing this always access the shared property.
class MainClass {
let apiHandler: APIHandler?
override func viewDidLoad(...) {
super.viewDidLoad(...)
apiHandler = APIHandler.shared
}
}

Angular 2: Change Detection of array inside the object

I have an object as follows which comes through #Input.
#Input() data;
//**
{
"class_a":["John","Harr y"],
"class_b":["Joseph","Phlip","David"],
"class_c":[]
}
**//
I need to detect the changes if data added or removed in class_a or class_b but im only getting change detection if values of objects are string.
Since the keys in my object are dynamic i couldn't iterate the object and create Iterable differs.
Is there anyway to detect changes of array inside the object.
My Implementation:
constructor(private differs: KeyValueDiffers) {
this.keyValueDiffer = differs.find({}).create();
}
ngDoCheck() {
let changes = this.keyValueDiffer.diff(this.data[this.component.factedBindKey]);
if (changes) {
console.log('Changes detected');
}
}
you can test like this
constructor(private cd: ChangeDetectorRef) {
}
ngOnChanges() {
let actualData =this.data
this.mymethod(actualData);
}
and call this line where you want to access that actual data like this
mymethod(data){
this.cd.detach();
//write main logic
}

ES6 Setters | error TS2300: Duplicate identifier

I am currently writing a class for an Angular 2 component that is using Input/Output decorators and a setter like so:
export class ItemDetails {
// Assign our `item` to a locally scoped property
#Input('item') _item: Item;
originalName: string;
selectedItem: Item;
// Allow the user to save/delete an item or cancel the
// operation. Flow events up from here.
#Output() saved = new EventEmitter();
#Output() cancelled = new EventEmitter();
// Perform additional logic on every update via ES6 setter
// Create a copy of `_item` and assign it to `this.selectedItem`
// which we will use to bind our form to
set _item(value: Item) {
if (value) this.originalName = value.name;
this.selectedItem = Object.assign({}, value);
}
}
I am pretty sure unless I missed something that this code should be fine, yet I get the error:
error TS2300: Duplicate identifier '_item'
Any insight as to why this is would be very much appreciated :)
To accomplish what I was trying to do, this revised class works fine:
export class ItemDetails {
#Input('item') set _item(value: Item) {
if (value) this.originalName = value.name;
this.selectedItem = Object.assign({}, value);
}
originalName: string;
selectedItem: Item;
#Output() saved = new EventEmitter();
#Output() cancelled = new EventEmitter();
}
A setter doesn't attach onto an existing property, it is its own class member - you can't define _item and then name a setter the same thing.

How does one reassign variables in an object?

For a class I'm taking, I need to reassign an object's properties to "Unknown". Here is the sample problem:
//In the function below, "person" will be passed in as an object that represents a person with properties such as name, age, gender, etc.
//Loop through all the properties of the object and set each value equal to "Unknown"
//For example, if "person" is {name: "Dolph L.", age: 33} then the function would return {name: "Unknown", age: "Unknown"}
function describePerson(person) {
//code here
}
If I'm understanding is correctly, it says that I must loop through the object and reassign it's properties to "Unknown". What I've been trying to do is this:
function describePerson(person) {
for (var prop in person) {
if (prop) {
return "Unknown";
}
}
}
I'm very new to Javascript and could really use some help here.
Thanks
for (var prop in person) {
if (person.hasOwnProperty(prop)) {
person[prop] = "Unknown";
}
}
return person;
You don't want to return in the loop, you want to modify each property of the object using the = operator.
The reason behind hasOwnProperty is the following.
person is an object. The object inherits properties from its Prototype. You don't care about those inherited properties, so you call hasOwnProperty which returns true if the property is one you gave it.

Can I add array accessors to generic TypeScript classes?

I have a list class that looks like this:
class List<T> {
private _array: Array<T>;
constructor() {
this._array = new Array<T>();
}
get count() { return this._array.length; }
public add = (state) => {
this._array.push(state);
}
...
}
And I would like to access the internal array from the class:
var something = list[0];
In c# I would do it something like this:
public T this[int index]
{
get
{
return _array[index];
}
private set {}
}
}
But I can't see anyway to accomplish this in TypeScript. Is there a way to add array accessors to my class so it looks more like a generic List ?
Thanks for the brainpower!
You can though the syntax is a bit weird. Note that since typescript gets compiled to js, only numbers and strings are valid keys:
interface IList<T> {
[index: number]: T
}
interface IMap<T> {
[index: string]: T
}
interface IMap<K, V> {
[index: K]: V // Error: Index signature parameter type must be either string or number
}
There's a trick to it though. You can't actually overload the operator, you can only tell the compiler that it exists. For instance if you have a generic object that you wish to use as a hashtable - declare it as Map<T> instead of any. The same goes for arrays.
The only possible way to actually put the operator in good use is to use an array or object as the underlying element, declare them as IList/IMap and then fiddle with their properties / prototype to add specific functionality. For example, to create an observable array see this answer

Resources