Implement conditional Routing in Angular - html

I am trying to implement the following functionality. When a button is clicked to check a condition, condition should be a variable (or a sum in my case) different from undefined (if different then success). Then either go to the success-page if the condition is met or to display the fail page if the condition is not met (+ if nothing was changed in the page just go to the success-page).
.html
<div class="d-flex justify-content-center">
<button type="button" (click)="updatePost()" routerLink="/success-page">Save</button>
The updatePost() method in the .ts file simply calls a function from the service and updates a user if some properties are changed (I have some input textboxes in the .html file).
updatePost() {
this.sharedservice.updateUser(this.user).subscribe(response => {
}, error => {
console.log(error);
})
}
I tried many ways but the functionality is not correct. The problem might be the order in which I tried to call the function and implement the logic.
Both pages are registered as routes.
const routes: Routes = [
{path: 'success-page', component: DisplaySuccessComponent},
{path: 'fail-page', component: DisplayFailPageComponent},
];

For that you should use Router from constructor. For that you need to provide constructor(private router: Router) {} then you need to check variable should not be undefined, null or not expected condition, then you need to route like
this.router.navigate(['fail-page']); and if not undefined, not null and as expected condition then you can navigate by using this.router.navigate(['success-page']);. So, your final code like below:-
// In HTML:-
<button type="button" (click)="updatePost()">Save</button>
// In ts:-
updatePost() {
this.sharedservice.updateUser(this.user).subscribe(response => {
this.router.navigate(['success-page']);
}, error => {
this.router.navigate(['fail-page']);
console.log(error);
})
}

you should not use routerLink in this case but navigate inside the upadtePost()function i.e:
updatePost() {
this.sharedservice.updateUser(this.user).subscribe(
response => {
this.router.navigate('/success-page');
},
error => {
console.log(error);
this.router.navigate('/fail-page');
});
}

Related

Does the routing paths order matter in angular?

I'm trying to make a router for one of my components, but it is not working as expected.
Initially it was working fine, but I had to add another route to decide which mat-tab would be open when redirecting. I added the second route like that, but for some reason the third one stopped working even though the first two were working fine.
import { Routes } from '#angular/router';
import { ActionComponent } from './action.component';
import { ActionResolver } from './action.resolver';
import { ACTION_RESULT_ROUTES } from './result/action-result.routes';
export const ACTION_ROUTES: Routes = [
{ path: ':id', component: ActionComponent, resolve: { action: ActionResolver } },
{ path: ':id/:tab', component: ActionComponent, resolve: { action: ActionResolver } },
{
path: 'action-result',
children: ACTION_RESULT_ROUTES,
},
];
I got a pretty large error when trying the third route, but it starts like this:
ERROR Error: Uncaught (in promise): TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.
Just in case, I tried to reorder it and all three were working fine when I did it like this:
export const ACTION_ROUTES: Routes = [
{ path: ':id', component: ActionComponent, resolve: { action: ActionResolver } },
{
path: 'action-result',
children: ACTION_RESULT_ROUTES,
},
{ path: ':id/:tab', component: ActionComponent, resolve: { action: ActionResolver } },
];
Can anyone tell me why it works like that?
Edit: Added the ACTION_RESULT_ROUTES for clarification
export const ACTION_RESULT_ROUTES: Routes = [
{ path: ':id', component: ActionResultComponent, resolve: { result: ActionResultResolver } },
];
According to Angular:
"The order of routes is important because the Router uses a
first-match wins strategy when matching routes, so more specific
routes should be placed above less specific routes."
It is recommended to have static routes first, therefore your action-result path should go first, followed by the :id/:tab path then :id path last. If you have a wildcard route, it should always be the last route in your array.
The reason behind this logic is that if you had the :id path above the action-result path, angular would use the word 'action-result' as the id in the :id path.
Similarly if you had the :id path above the :id/:tab path, angular would use the words id/tab as the id in the :id path.
So, a rule of thumb is to always put your static routes first, then your dynamic routes from the most specific to the least specific followed by your wildcard route at the end.
E. G.
PATH1
PATH2
PATH3/:USER/:ROLE/:PAGE
PATH4/:SITE/:ID
PATH5:/ID
Wildcard route (*)

Get json data in VueJS

onMounted(() => {
productService.value
.getProducts()
.then((data) => (products.value = data));
console.log((products))
});
When I print products with console.log, here what I have.
capture of the console
I see that the data I want are in RawValue but I don't know how to access them.
I tried Object.values(products) or just console.log(products._rawValue) or console.log(products.rawValue) it print undefined.
Do you know what function call ?
Thanks
There are 2 issues
#1 - you're using console.log(products) which shows you the reactive object, what you need instead is console.log(products.value) which will only show the value, which should match the content of data.produtcs
#2 - you might find that 👆 now shows an empty result. The reason that's happening is that you're calling the console log after the async function, but before it finishes, so you're calling it before it has a chance to update. To fix that, you can log as part of the async function
onMounted(() => {
productService.value
.getProducts()
.then((data) => {
products.value = data;
console.log(products.value);
})
});
If you're using the products inside a template, you don't need to worry about what's before or after the async function since it will re-render the component on change.
Also, you probably don't need to define productService as a ref, the class is likely not something that needs to be reactive, so you can just do simple assignment and then skip the .value to call getProducts
with axios what I do is take out the data with response.data you could try
onMounted(() => {
productService.value.getProducts().then((response) => (
products = response.data
));
console.log(products.length);
});

React Native - FlatList Not Render TO Binding Another Componet

here some error in flatlist rendering time the following details are describe in this image. please help me for this issue
Remove the following code
if(!dataSource) {
return null;
}
Change your renderItem like
renderItem={ ({ item, index }) => {
return ...
}}

Unit test a V-If with Jest

How do I test the following v-if on my parent component using Jest?
Parent:
<div class="systemIsUp" v-if="systemStatus == true">
foo
</div>
<div class="systemIsDown" v-else>
bar
</div>
<script>
export default {
name: 'File Name',
data () {
return {
systemStatus: null,
}
},
</script>
Here is my current setup for testing if those divs render when I change the value of the systemStatus variable
Unit Test:
import { shallowMount } from '#vue/test-utils'
import FileName from 'path'
describe('FileName', () => {
//Declare wrapper for this scope
const wrapper = shallowMount(FileName)
it('Should display message saying that the system is down if "systemStatus" data variable is false', () => {
expect(wrapper.html().includes('.systemIsDown')).toBe(false)
wrapper.setData({ systemStatus: false})
expect(wrapper.html().includes('.systemIsDown')).toBe(true)
});
});
I have tried using contains and toContain instead of includes but still cannot get it to work, Jest returns the following:
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
expect(wrapper.html().includes('.systemIsDown')).toBe(false)
wrapper.setData({ systemStatus: false })
expect(wrapper.html().includes('.systemIsDown')).toBe(true)
^
Clearly it cannot see the systemIsDown div at all and does not think it exists hence why the first expect passes but how can I get it to see the div when the systemStatus variable is updated?
Thanks
Changed around the assertion to look for specific CSS selector as follows:
wrapper.setData({ systemStatus: false})
expect(wrapper.find(".systemIsDown")).toBeTruthy()
This should work, if you want to check given DOM element has been created (or not):
expect(wrapper.find(".systemIsDown").exists()).toBe(true) // or false
more here

How to make use of :id returned by stateParams of stateProvider in angularJS

Am looking to read & display this JSON array of objects.
[
{
"pictitle":"title1 ",
"thumbpicurl":"url1",
"bigpicurl":"url2",
"picdescription":"text text"
},
{
"pictitle":"title2 ",
"thumbpicurl":"url1",
"bigpicurl":"url2",
"picdescription":"text text"
},
]
JSON is served by this factory.
angular.module('picService', ['ngResource'])
.factory('picsFactory',function($resource){
return $resource('pictures.json',{},{
'getData': {method:'GET', isArray:true}
}
);
});
This Markup displays mini thumbnails using the thubmpicURL of the JSON data.
<div class="miniImages">
<a href="/home/{{$index}}">
<img src="{{pic.thumbpicurl}}" class='thumbnail'/> </a>
</div>
Am using stateProvider for routing to display enlarged version of the picture when user selects a thumbnail.
$stateProvider.state( 'home/:id', {
url: '/home/:id',
views: {
"main": {
controller: 'picCtrl',
templateUrl: 'home/pics-detail.tpl.html'
}
}
});
First controller returns the JSON picture data.
.controller('HomeCtrl', function HomeController( $scope,picsFactory ) {
picsFactory.getData(function(picturedata){
$scope.picParams = picturedata;
});
})
Second controller is looking to set properties of each picture object. Am not sure what is the correct syntax to set the stateParams to the picture object.
.controller('picCtrl', function picController( $scope, $stateParams ) {
$scope.picture = $scope.picParams[$stateParams.id];
})
;
I get this error in the debuge console. I think it doesn't like my $scope.picParams[$stateParams.id] in picCtrl controller.
Is this the correct way to make use of $stateParams
TypeError: Cannot read property '0' of undefined
--
ANSWER:
I modified picCtrl to inject picsFactory and with this change it looks to work now.
.controller('picCtrl', function picController( $scope, $stateParams, picsFactory ) {
picsFactory.getData(function(picturedata){
$scope.picture = picturedata[$stateParams.id];
});
})
;
The reason for this could be that the async call of getData on HomeCtrl may not be complete before your second controller picCtrl is initialized and hence picParams is null.
Also HomeCtrl should be parent state or declared on parent html of ui-view for the picCtrl to be able to access what has been set by HomeCtrl