I have a VueComponent for which I need to pass a value "A". the problem is the value A can be passed VueRouter parameter or via the template interpolation. What is the best way to set a property data via both options?
e.g.
<component :property="value"></component>
if I navigate to
/component/8/edit
mounted() {
this.property = this._route.params.id
}
You have to figure out to which parameter you want to give priority, If you want to give priority to route param, you can do following:
mounted() {
this.property = this.$route.params.id ? this.$route.params.id : this.property
}
If you want to give priority to props being passed, you can write:
mounted() {
this.property = this.property ? this.property : this.$route.params.id
}
Related
In my first component I have set up a property like so:
linkEnabled: boolean = false;
and when this is set to false, certain routes will not be able to be accessed by users which I've set up in my html file like so:
<a class="nav-link" [routerLink]="linkEnabled ? ['/libraries']: null" [routerLinkActive]="linkEnabled ? 'active-route' : 'is-disabled'">
This is set to false until a project has been selected, this is done in another component
In the second component I've imported the first one like so:
import { NavSidebarComponent } from '../nav-sidebar/nav-sidebar.component';
and added it to the constructor:
constructor(private store: Store<AppState>,
..........
private navSidebarComponent: NavSidebarComponent
) { }
and in the ngOnit, where the project is set, I call the linkEnabled value and set to true for when project name is not null:
this.projectNameSub = this.store.pipe(select(ProjectSelectors.selectCurrentProjectName))
.subscribe(projectName => {
this.projectName = projectName;
if(this.projectName !=null) {
this.navSidebarComponent.linkEnabled = true;
}
});
The issue I am having, is that I am not sure how to get the first component to listen to the changes so that it know that linkEnabled has now been set to true? As at the moment it just sees it as false so I know I am missing a step but I'm just not sure what. Is there a way to subscribe to the value so that it can listen to it changing in the ngOnInit in the first component?
I had thought of creating a function like so within the first component:
public activateRoutes(): Observable<boolean> { console.log("activate routes called"); return of(this.linkEnabled = true); }
and then in the ngOnit do something like:
this.activateRoutes().subscribe((link) => { this.linkEnabled = link; })
and then in the ngOnit in the second component, instead of doing:
this.navSidebarComponent.linkEnabled = true;
I would do: this.navSidebarComponent.activateRoutes();
However all that is happening is that on page load, the linkEnabled is set to true and it's not working at all as I need it to
Solved this issue by creating new action, reducer and selectors file to store this in the store and could then do:
this.routeEnabledSub = this.store.pipe(select(RouteSelectors.selectRouteEnabled))
.subscribe(routeEnabled => {
this.routeEnabled = routeEnabled;
});
in the first component
and then in the second one, update it like so:
if(this.projectName !=null) {
this.store.dispatch(RouteActions.setRouteActive(
{ routeActive: true }));
} else {
this.store.dispatch(RouteActions.setRouteActive(
{ routeActive: false }));
and in html check for linkEnabled being set like so:
[routerLinkActive]="linkEnabled ? 'active-route' : 'is-disabled'"
Is there a way with Sinon to have a negative match? Specifically that an object does not have a given property?
Thanks!
There isn't currently a built-in matcher for that.
Sinon allows you to create custom matchers so you could create your own, here is one for doesNotHave based on the built-in has matcher:
import * as sinon from 'sinon';
const doesNotHave = (prop) => sinon.match(function (actual) {
if(typeof value === "object") {
return !(prop in actual);
}
return actual[prop] === undefined;
}, "doesNotHave");
test('properties', () => {
const obj = { foo: 'bar' };
sinon.assert.match(obj, sinon.match.has('foo')); // SUCCESS
sinon.assert.match(obj, doesNotHave('baz')); // SUCCESS
})
I've just realized that it's possible to specify undefined in the object's shape to make the check:
sinon.assert.match(actual, {
shouldNotExists: undefined
});
Not completely sure if it's 100% valid, but seems to do the job.
You cannot use sinon for this, you have to use something like chai.
You would do:
cont { expect } = require("chai");
expect({ foo: true }).to.not.have.keys(['bar']);
https://runkit.com/embed/w9qwrw2ltmpz
I have a parent component, this a very scaled down version.
I define type State (as example shows)..... and then I pass down a portion of (their values) them into a child component. That child component (in a seperate file) again, defines its props.... but I am getting errors for every single prop in the parent. infuriating.
for each prop being passed to the "MyChildComponent", I am getting this error:
props of React element MyChildComponent. This type is incompatible with object type
type State = {
name: string,
age: number,
shoe: number,
hair: string
}
class Dude extends component<void, Props, State> {
props: Props;
state: State;
// these values get over-written by some ajax call
constructor() {
this.state = {
name: 'george',
age: 999,
hair: 'brown',
shoe: 11
}
displaySomeComponent = (): React.Element<*> => {
const { name, age, hair } = this.state;
return (
// EACH ONE OF THESE GIVES AN ERROR
//Flow: props of React element `MyChildComponent`. This type is incompatible with object type
<MyChildComponent
name={name},
age={age},
hair={hair}
/>
)
}
}
// In a separate file for MyChildComponent
// No errors in this file
type Props = {
name: string,
age: number,
hair: string
}
class MyChildComponent extends component<void, Props, void> {
props: Props;
render() {
// all renders fine
}
}
I am at my wits end. I do not understand what is going on, as I've passed things into many child components, but this is mucking up. I am thinking it might have something to do with the destructuring?
Hmm, it's hard to say. If I fix a few syntax errors, this seems to work fine in Flow 0.54: my version
To track down what is wrong, you might try adding type declarations to see where things go wrong. Like, inside the parent render method, under the destructuring, try adding name: string; and see if Flow complains about that.
I have been facing some issues with the native base checkbox and AsynStorage. In fact, AsynStorage only accepts strings by default BUT can store boolean variables also, I tried to use that method but I get a string stored every time.
While the checkbox does only accept boolean variables and throws a warning if I tried to use a string and it does not show the previous state of the checkbox (checked or not ).
So, I decided to make my own checkbox using TouchbleOpacity .. So do you guys have any idea how to make it ?
Here is the result i want to achieve:
So, the purpose is to make a checkbox settings page that controls the style of a text in another page and to get the checkbox as left the previous time, for an example : if I check it , I change the page and go back again to the settings page , I need to find it checked (indicating the previous state)
The code is
in the settings page :
toggleStatus() {
this.setState({
status: !this.state.status
});
AsyncStorage.setItem("myCheckbox",JSON.stringify(this.state.status));
}
// to get the previous status stored in the AsyncStorage
componentWillMount(){
AsyncStorage.getItem('myCheckbox').then((value) => {
this.setState({
status: value
});
if (this.state.status == "false") {
this.setState({
check: false
});
}
else if (this.state.status == "true") {
this.setState({
check: true
});
}
if (this.state.status == null) {
this.setState({
check: false
});
}
});
}
render {
return(
...
<CheckBox
onPress={() => { this.toggleStatus() }
checked={ this.state.check }/>
)}
In other page :
componentDidMount(){
AsyncStorage.getItem('myCheckbox').then((value) => {
JSON.parse(value)
this.setState({
status: value
});
});
}
This code change the status after TWO clicks and I don't know why and i get this weird output in the console, every time I click the checkbox
If you take a look at AsyncStorage documentation, you can see that, in fact, the method getItem() will always return a string (inside the promise).
For the problem with the AsyncStorage you should consider trying to parse this string returned to a boolean using this method explained here and then use this parsed value inside the native base checkbox.
But if you want to do your own component, try doing something like this:
export default class Checkbox extends Component {
constructor(){
super();
this.state = { checked: false }
}
render(){
return(
<TouchableOpacity
onPress={()=>{
this.setState({ checked : !this.state.checked });
}}
>
<Image source={this.state.checked ? require('checkedImagePath') : require('uncheckedImagePath')} />
</TouchableOpacity>
);
}
}
You will need to set some style to this image to configure it the way you want.
-- Based on your edition:
I can't see nothing wrong on your toggleStatus() method in settings page, but try changing your componentWillMount() to this:
componentWillMount(){
AsyncStorage.getItem('myCheckbox').then((value) => {
if (value != null){
this.setState({
check: (value == 'true')
});
}
});
}
However in the other page the line you do JSON.parse(value) is doing nothing, once you are not storing the result anywhere.
I've encountered a problem with rendering some elements in React.
(I use ImmutableJS)
renderComponents: function(components) {
if(components.isEmpty()) return [];
var table = [];
components.map(function(component) {
table.push(<ComponentTableElement key={ component.get('id') } data={ component } />);
if(component.has('children')) {
var children = component.get('children');
table.concat(this.renderComponents(children));
}
});
return table;
},
As I looked for error, I found that this.renderComponents(children) doesn't return anything at all and the code somehow stops.
I mean before that line everything works ok, but then after this line, when i try to console.log something, it doesn't show up. And it doesn't even reach return table.
So what is wrong with that code?
In the context of the function you pass to map, this refers to the window object, not to the current component instance, so this.renderComponents is undefined when you try to call it.
components.map(function(component) {
this === window;
});
You can pass a value to use as this in the body of your function as the second parameter of Array::map.
components.map(function(component) {
table.push(<ComponentTableElement key={ component.get('id') } data={ component } />);
if(component.has('children')) {
var children = component.get('children');
// here, `this` refers to the component instance
table.concat(this.renderComponents(children));
}
}, this);
If you're using ES6, you can also use fat-arrow functions, which are automatically bound to this.
components.map((component) => {
table.push(<ComponentTableElement key={ component.get('id') } data={ component } />);
if(component.has('children')) {
var children = component.get('children');
// here, `this` refers to the component instance
table.concat(this.renderComponents(children));
}
});