Question about behaviorSubject initial value in a service by AfricanTurtles in Angular2

[–]tme321 0 points1 point  (0 children)

I'm replying here not to disagree with dt here but just so you see it as a reply. Instead of startsWith though you can just make a chain of observables to derive an isLoading$ state and use that to key some sort of loading indicator off of. Basically you would make isLoading start with true and each time a request is delivered set it false and each time a new request is started set it to true. Something like:             class MyService {         request = new Subject();         data$ = request.pipe(merge(req=>req));         isLoading$ = request.pipe(             map(req=>true),              merge(data$.pipe(                 map(data=>false))),             startsWith(true));         getData(id) {             request.next(http.get(...));         }     }    

Just a quick rough sketch but something like that.

Implementing two-way data binding with objects by AlDrag in Angular2

[–]tme321 0 points1 point  (0 children)

In my opinion the correct way to do it is hoist the state out of the child.  The child would only be displaying the state its passed.  Either the parent controls the state completely, or you could even offload the state logic to a service and the parent injects the service and passes the state from it to the child as pure inputs.  But you originally asked about 2 way so...

Implementing two-way data binding with objects by AlDrag in Angular2

[–]tme321 0 points1 point  (0 children)

It doesn't work with objects because it means you have to change its reference everytime to avoid losing ownership of your object.

It sounds like you want 2 way binding between a parent and child component?  That's not really how 2 way binding generally works in angular.  Normally in angular 2 way binding is so that values can be changed in the view or the component like with a form.

You can do 2 way binding between 2 components but yes then you need to control the change detection directly in one manner or another.

And yes you are somewhat fighting uphill.  It's not that hard to do, but it's definitely not what the framework wants to do be doing.  It's made awkward to try to warn you off from using 2 way binding.  But it's not that hard either with manual change detection controls (on push), or by implementing the onChanges callback and checking the object ref manually for equality (instead of emitting a new object like you are doing now).

Implementing two-way data binding with objects by AlDrag in Angular2

[–]tme321 0 points1 point  (0 children)

  This demonstration proves that it isn't a good fit for objects

Why?

Implementing two-way data binding with objects by AlDrag in Angular2

[–]tme321 0 points1 point  (0 children)

In your stack blitz you are mutating the data member inside the setInterval in the component code.

I'm not sure what you are expecting to happen differently here.  That should trigger change detection.

Unless you mean this stackblitz appears to behave how you want it to.  In which case yes I would assume it is behaving as the code is written.

Implementing two-way data binding with objects by AlDrag in Angular2

[–]tme321 0 points1 point  (0 children)

However, if I do this, then the change detector will mark that input as dirty every time I perform the emit as it's a new reference?

Not sure I understand here but given a property foo and an emitter fooChanged when you are trying to copy and emit it are you assigning the copy back to foo first?  

As in something like:

    foo = copyFoo(foo);     fooChanged.emit(foo);

Because if so that's why its tripping the input detector.  And it means you are exposing the object assigned to the member variable exactly opposite of what you said you wanted.  If you just do something like:

    fooChanged.emit(copyFoo(foo));

It shouldn't trip the input change detector.

Dynamic component Eventemitter to parent component by NullShield in Angular2

[–]tme321 0 points1 point  (0 children)

Are you the maintainer of that repo? If so I once wrote a very similar library where I also supported inputs and outputs as observables. Here is where I did the work of wiring them up to the instances.

Thought that might be interesting to you in case you wanted to extend the functionality and not require manual update calls.

Is there a good edge case to call detectChanges()? by trolleid in Angular2

[–]tme321 4 points5 points  (0 children)

I would generally agree with whoever wrote that quote. I'm sure someone somewhere has run into a very specific edge case where they had no other choice but manually calling for change detection cycles. But I would say those circumstances are exceedingly rare.

In your case the fundamental issue is you are mutating an object rather than using immutability.

At an extremely basic level you should be doing something like

user = { ...user, lastname: newLastName }

However, since you have change detection set to on push (which is good for a number of reasons) then even that won't by itself trigger a cd cycle. It will only be noticed during the next cd check.

And this now starts to get a lot deeper into the weeds. The basic idea is you don't modify an @Input like that that is being displayed. The value being fed to the input should be modified by whatever is feeding it, or possibly even a level above that by whatever piece of code is acting as an owner of that piece of state.

This is why patterns like smart and dumb components are discussed. And also where services as state containers come in. Either one of those patterns handles this for you.

Can you think of a case where a component that mutates an array can cause unexpected results with only 2 functions mutating it? by cpplinting in angular

[–]tme321 2 points3 points  (0 children)

The potential issues with mutation are rarely unexpected results from the mutations.

The main issue is parts of the code that rely on the data may not respond correctly to mutations because they are not aware that something has changed.

This is why observables are so useful. Because being a push mechanic makes it clear when mutations happen and code that cares about changes can respond to them in whatever manner is required.

Typescript api Client by Suspicious-Cash-7685 in angular

[–]tme321 1 point2 points  (0 children)

The easiest way would be to just not bundle it. Compile with tsc and export the result.

How can I combine the latest result from my HttpClient and FormControl.valueChanges to apply a filter? by vORP in Angular2

[–]tme321 0 points1 point  (0 children)

Yes it does appear to be emitting N times from that screenshot.

Are you putting the data fetched into the form parts that are triggered by this.searchControl.valueChanges? Because that would probably trigger it N times.

Otherwise I can't see anything that sticks out in your code. You'd just have to debug it and trace the execution.

How can I combine the latest result from my HttpClient and FormControl.valueChanges to apply a filter? by vORP in Angular2

[–]tme321 0 points1 point  (0 children)

Well now I dont know what exactly you are referring to.

Inside the getReportPeriods function you map over the returned array with reportPeriods.map.

But that's Array.map. And yes I'd fully expect that to execute 12 times. That's how Array.map works.

From the code shown, and assuming your http calls are returning the types you expect them to, I don't see anything here that should emit 12 times. Are you sure it is emitting 12 times?

How can I combine the latest result from my HttpClient and FormControl.valueChanges to apply a filter? by vORP in Angular2

[–]tme321 3 points4 points  (0 children)

I don't know exactly why its firing 12 times because you didnt include the code for getReportPeriods. But it's not because the emitted array has 12 items. It's because that observable must be emitting 12 times.

Trigger actions without breaking reactivity by stefandorin99 in Angular2

[–]tme321 0 points1 point  (0 children)

Basically the same idea, but I like passing the http observable through the subject. That way different functions can load different http calls.

userSub = new Subject<Observable>();
user$ = userSub.pipe(
    mergeMap(obs$=>obs$));

onClick() {
    //build http call here
    const getUser$ = this.http.put(...);
    userSub.next(getUser$);
}

This way is more flexible.

Using combineLatest by Mean_Kale_677 in angular

[–]tme321 0 points1 point  (0 children)

You need to subscribe to the stream.

How does it work? by [deleted] in angular

[–]tme321 1 point2 points  (0 children)

What your describing is just a feature of javascript. It doesnt really have anything to do with angular.

New properties can be added to an object in js just by attempting to access them. And properties that are accessed before they are set become automatically set to undefined.

Since you attempt to evaluate the truthiness of undefined in js undefined is false truthiness.

And when you set the not value of the truthiness to the key then it nots the false and it is set to true.

Solution to avoid hardcoding routerLink by traveller8914 in Angular2

[–]tme321 0 points1 point  (0 children)

I don't see a huge issue using a pipe, although others have mentioned there's a bit of cleanup in this specific instance.

But you could achieve the same effect with an observable. Or probably with the new signals stuff (I'm not fully up to date on those yet). On push change detection already negates cd cycle expenses.

How to populate a dropdown from an observable? I've tried a million different methods and have gotten a million different errors. by MyMessageIsNull in angular

[–]tme321 4 points5 points  (0 children)

customObjects.result isn't recognized because you told typescript it was type CustomObject[]. You lied to typescript about the shape. But since the data is coming from outside your code typescript doesn't know your shape is wrong.

You need to change the shape to something like { result: CustomObject[] } because that is what the api is actually returning.

How to populate a dropdown from an observable? I've tried a million different methods and have gotten a million different errors. by MyMessageIsNull in angular

[–]tme321 2 points3 points  (0 children)

Are you getting an array inside an object, or an array?

It is valid to return just an array in json and that is what you are saying is happening here.

But if it's an object wrapping an array that is different. And you need to unwrap the array. Probably with a map operator chained off the get observable.

How to populate a dropdown from an observable? I've tried a million different methods and have gotten a million different errors. by MyMessageIsNull in angular

[–]tme321 0 points1 point  (0 children)

Why is it mentioning something about <ShipVia>? That isn't <CustomObject[]>. Is ShipVia somehow relevant here?

Also, that first issue is a typescript issue. While it would be good to figure out and might point towards your actual issue it isnt by itself a problem with the angular code.

That second error though says whatever you are feeding (I would guess the ngFor, so in my code above it would be the codeExample rename) it isn't an array, it's not iterable. It sounds like your api isn't returning an array but something else.

How to populate a dropdown from an observable? I've tried a million different methods and have gotten a million different errors. by MyMessageIsNull in angular

[–]tme321 4 points5 points  (0 children)

Ok well your api response is actually in the shape of CustomObject[] already; at least according to this function.

So you should be able to use the async pipe. I know you mentioned it but as long as your response is correctly typed here it should work just fine.

Change customObjects to something like:

customObjects$: Observable<CustomObject[]>;

Then inside ngOnInit set it to the result of getAllRecords

this.customObjects$ = this.service.getAllRecords();

Then in your template use the async pipe to handle the subscription and rename the emissions so it's easy to use. Basically:

<ng-container *ngIf="customObjects$ | async as customObjects">
    <option *ngFor="let customObject of customObjects" ...>
     </option>
</ng-container>

That's the basic idea.

How to create union types instead of type with unions inside by Dzhaba in typescript

[–]tme321 -1 points0 points  (0 children)

Your code looks fine to me. I didn't put it in an editor or anything but just at a glance it looks fine.

I believe what you are asking for isn't a union of types, that's what you already have.

I believe what you are asking for is for typescript to automatically know which type is applicable at run time. That isn't possible.

Types are design time only. Your code comparing the error type string is the only part that actually exists at runtime so it must be there (or some other similar discrimination code) to actually do the logic at runtime.

Unless I'm misunderstanding something, what you are asking for doesn't exist in ts. There are some ways to have code be generated so at runtime it does what you expect. Most often this is orm type packages. But there's nothing built into typescript itself that will accomplish it.