problems in using custom Hook - react-hooks

I am starting with react just learning to create Custom hooks,but having issue with while creating this custom hook to turn a sentence to sentence case.There is no error and also not showing the output(I want like "HeLLO WORld" to as "Hello world")Can't find out where I am making the mistake,kindly help me out.Here is the code
The custom hook-
import UsePascalCase from "../CustomHooks/UsePascalCase"
export default function TextBoxDemo(){
var text="";
function handleOnInputEntry(e){
text=e.target.value
}
var pascal=UsePascalCase(text)
return(
<>
<textarea onChange={handleOnInputEntry}></textarea>
<span>{pascal}</span>
</>
)
}
The input box,where want to use the hook
export default function UsePascalCase(str){
var firstCharacter=str.charAt(0).toUpperCase();
var restCharacters=str.substring(1).toLowerCase();
var sentence=firstCharacter+restCharacters
return sentence
}

Your text variable needs to be reactive to see changes in your application. More info: https://reactjs.org/docs/hooks-state.html
Try:
import UsePascalCase from "../CustomHooks/UsePascalCase"
import { useState } from "react"
export default function TextBoxDemo(){
const [text, setText] = useState("");
function handleOnInputEntry(e){
setText(e.target.value)
}
var pascal=UsePascalCase(text)
return(
<>
<textarea onChange={handleOnInputEntry}></textarea>
<span>{pascal}</span>
</>
)
}

Related

How to update root level component data

I can't get how to initialize a root component data field into a blade view. In particular:
app.js:
import { createApp } from 'vue'
const app = createApp({
data() {
return {
count: 0
}
}
});
blade view:
...html...
<script>
// how can I update count with a blade var (i.e. {{ $count }}) created in my controller?
</script>
In Vue2 actually it was pretty easier, but I'm getting so crazy to get this out that I'm supposing this pattern is not good at all...
Thanks in advance for your kind support.

How to use RXJs Subject like store variable in Svelte

How to use RXJs Subject like store variable in Svelte? You can use the Subject variable in Svelte with $ prefix. But when you bind the variable to input it throws an exception: "Error: name.set is not a function" because the Subject type has not a set method.
You can use RxJs Subject like a store variable in Svelte as in the example below.
<script>
import {Subject} from "rxjs";
let name = new Subject();
setTimeout(()=>{name.next("text")}, 1000);
</script>
<h1>Hello {$name}!</h1>
But if you try to use the name variable with a bind directive it throws an exception: "Error: name.set is not a function".
<script>
import {Subject} from "rxjs";
let name = new Subject();
$: console.log($name);
</script>
<h1>Hello {$name}!</h1>
<input bind:value={$name} />
To solve this issue, you can add a set method to the Subject class with a simple trick :).
<script>
import {Subject} from "rxjs";
Subject.prototype.set = function (value) {
this.next(value);
}
let name = new Subject();
$name = "Ali";
$: console.log($name);
</script>
<h1>Hello {$name}!</h1>
<input bind:value={$name} />

MatPaginator gets undefined

I have replicated thsi case: Angular 5 Material Table not getting data from service
But when I try access any property from paginator I get undefined error from this objet.
Any ideas?
Thanks
I got the same issue. Placing mat-paginator tag outside *ngIf resolved my issue. Make sure it is available to component class without any conditions.
Some issues that may cause mat-paginator is undefined:
You forgot to import in app.module.ts import { MatPaginatorModule } from '#angular/material'; and then declare the import in the imports array inside ngModule.
#NgModule({ declarations: [ somestuff], imports: [ MatPaginatorModule]});
Import MatPaginator inside the component you are using:
import {MatPaginator, MatSort, MatTableDataSource} from '#angular/material';
set the MatDataSource to be none. (only need to do this if you are going to be getting async data e.g. from a server)
this.dataSource = new MatTableDataSource([]);
Make sure you set the length property of the mat-paginator to the length of the data rows returned.
Set the paginator inside NgAfterViewInit method or if that doesn't work try:
private paginator: MatPaginator;
private sort: MatSort;
#ViewChild(MatSort) set matSort(ms: MatSort) {
this.sort = ms;
this.setDataSourceAttributes();
}
#ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
this.paginator = mp;
this.setDataSourceAttributes();
}
setDataSourceAttributes() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
if (this.paginator && this.sort) {
this.applyFilter('');
}
}
In some cases, the issue is related to conditional outer div. Ex:
<div *ngIf="condition">
...
<mat-paginator ....>
</div>
For a such scenario just replace *ngIf="condition" with [hidden]="!condition" and it'll work.
Please refer to https://github.com/angular/components/issues/10205 for more details
I had a similar problem and this is how I got it working:
My Initial Code Setup
component.html
<div class="chart-wrapper" *ngIf="viewType === 'chart'; else table;">
// Load Chart Here
</div>
<ng-template #table>
// Load Table Here
<mat-paginator
#paginator
[length]="tableDataSource.data ? tableDataSource.data.length : 0"
[pageSize]="pageSize"
[pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)"
></mat-paginator>
</ng-template>
component.ts
columns: string[] = [];
tableDataSource: MatTableDataSource<any[]> = new MatTableDataSource([]);
#ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
pageIndex = 0;
pageSize = 10;
pageSizeOptions = [10, 15, 20];
ngOnInit() {
this.getTableData();
}
ngAfterViewInit() {
this.tableDataSource.paginator = this.paginator;
}
getTableData() {
// After getting data from API
this.tableDataSource.data = apiResponse;
}
The Solution
Put static: false while declaring Mat Paginator
#ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
and then set paginator onto tableDataSource after data gets loaded into it
this.tableDataSource.data = apiResponse;
this.tableDataSource.paginator = this.paginator;
Thanks to the solution by cisco336 on this thread
To my surprise nobody appraised that solution.
For me it was broken after angular upgrade from 7 to any version(although i checked in only angular 12).
In Angular 8 they introduced a parameter where we are supposed to give {static: true} if we need the value in ngOninit. From Angular 9 it was set to false by default if we are not mentioning it explicitly.
So changing code from this
#ViewChild(MatPaginator) paginator: MatPaginator;
To this
#ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
Fixed my issue.
"Inserting an *ngIf means that its contents cannot be queried until the view is initialized with change detection. This means the query for sort is empty at ngOnInit.
This can be resolved by changing the setup from ngOnInit to ngAfterViewInit. https://stackblitz.com/edit/angular-mewfek?file=src/app/app.component.ts "
reference
https://github.com/angular/components/issues/15966
In my case, paginator object was getting initiated in ngOnInit() and giving exception paginator is undefined.
Initial code i.e. not working code:
ngOnInit() {
this.dataSource = new StoreServiceDataSource<User>(this.userService, this.snackBar);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
After correction i.e. working code:
ngAfterViewInit() {
this.dataSource = new StoreServiceDataSource<User>(this.userService, this.snackBar);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
Just changed initializing life cycle hook. Earlier paginator was getting initialized in hgOnInit(), now it's initialized in ngAfterViewInit().
[length]="dataSource.filteredData.length" over "mat-paginator" worked for me.
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10,25,50]" #paginator [length]="dataSource.filteredData.length"[showFirstLastButtons]="true"></mat-paginator>
MatPaginator being undefined most likely means you do not have the module imported. Sometimes angular mat does not explicitly tell you these things that you are missing. But always check the API tab under their documentation before using a component. At your module level, you should have the following in your app.module.ts file.
the import
import { MatButtonModule, MatTableModule, MatPaginatorModule, MatProgressSpinnerModule, MatTableDataSource } from '#angular/material';
Your component imported that used paginator of course
import { TableComponent } from './table/table.component';
Those modules imported in your imports array
imports: [
BrowserAnimationsModule,
NgbModule.forRoot(),
FormsModule,
RouterModule,
AppRoutingModule,
CommonModule,
MatButtonModule,
MatTableModule,
BrowserAnimationsModule,
MatPaginatorModule,
MatProgressSpinnerModule,
HttpClientModule
],
And those modules exported if necessary (different topic so I wont discuss here).
exports: [
MatButtonModule,
MatTableModule,
MatPaginatorModule
],
This is all happening in my App.Module
export class AppModule { }
This assuming you do bot have your project structured as feature modules. In that case you would really only need everything I talked about in the module in which your component lives. But in this case, where everything is under the app module, this works just fine.
<div class=" fixed-form-bottom" [hidden]="changeState">
<div class="team-footer">
<mat-paginator #paginator [pageSize]="pageSize" [showFirstLastButtons]="true" [length]="totalSize"
[pageIndex]="currentPage" (page)="pageEvent = handlePage($event)" [hidePageSize]="true">
</mat-paginator>
</div>
</div>
And in .ts file , you compare your condition and pass true/ false from there
if(this.totalSize>3){
this.changeState=true;
}
its worked for me
Check if you have *ngIf that wrap your mat-paginator or any top component, if you need hide you should use [hidden] attribute in your component
Another reason for the delay in pagination injection is one or more missing end tag such as within your html markup, which seems to impact the timing of the pagination markup DOM injection.
In this type of problem scenario a 2nd+ load of the table will show the pagination components.
There are two solutions to this problem
Solution 1:
If mat-paginator is inside *ngIf then either take it outside or use [hidden] attribute.
<div [hidden]="condition">
</div>
Solution 2:
Make sure you are not using static: true while initializing the paginator
#ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
change it to
#ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;

Routing Issues in React-Redux

I'm new to the React-Redux ecosystem, learning by trying out simple applications.
In this case I'm trying out how routing works in the react-redux application.
Basically, the idea is :
Navigate to a new page by clicking a Link( a react-router
component)
Navigate to a new page upon successful completion of dispatched async action.
Here's my code
import React from 'react'
import {Link} from 'react-router'
import {routerActions} from 'react-router-redux'
import {connect} from 'react-redux'
class App extends React.Component {
render() {
// And you have access to the selected fields of the State too!
return (
<div>
<header>
Links:
{' '}
<Link to="/">Home</Link>
{' '}
<Link to="/foo">Foo</Link>
{' '}
<Link to="/bar">Bar</Link>
</header>
<div>
<button onClick={() => routerActions.push('/foo')}>Go to /foo</button>
</div>
</div>
)
}
}
export default connect(null, null)(App);
===================================================================
import React from 'react'
import {connect} from 'react-redux'
class Foo extends React.Component {
render() {
return (
<div> <h1>I'm Foo</h1> </div>
)
}
}
export default connect(null, null)(Foo);
===================================================================
import React from 'react'
import {connect} from 'react-redux'
class Bar extends React.Component {
render() {
return (
<div> <h1>I'm bar</h1> </div>
)
}
}
export default connect(null, null)(Bar);
===================================================================
import React from 'react'
import ReactDOM from 'react-dom'
import {Provider} from 'react-redux'
import {Router, Route, browserHistory} from 'react-router'
import {syncHistoryWithStore} from 'react-router-redux'
import configureStore from './store'
import App from './components/test/App';
import Bar from './components/test/Bar';
import Foo from './components/test/Foo';
// Get the store with integrated routing middleware.
const store = configureStore()
// Sync browser history with the store.
const history = syncHistoryWithStore(browserHistory, store)
// And use the prepared history in your Router
ReactDOM.render(
<Provider store={store}>
<div>
<Router history={history}>
<Route path="/" component={App}>
<Route path="/foo" component={Foo}/>
<Route path="/bar" component={Bar}/>
</Route>
</Router>
</div>
</Provider>,
document.getElementById('root')
===================================================================
import {combineReducers,createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import createLogger from 'redux-logger'
import userReducer from './reducers/reducer-user';
import {routerMiddleware,routerReducer} from 'react-router-redux'
import {browserHistory} from 'react-router'
export default function configureStore() {
// Create the routing middleware applying it history
const browserMiddleware = routerMiddleware(browserHistory);
const logger = createLogger();
const reducer = combineReducers({
userState: userReducer,
routing: routerReducer
})
const store = createStore(reducer,applyMiddleware(thunk,browserMiddleware,logger));
return store;
}
The application builds fine and it comes up well but when i click on the link, it does not work.
See screen shot of the running application
Searched around and read various posts but i could not pinpoint the root problem.
Your code seems to be correct, but there is a simple thing you are missing: you are not rendering the "child" of your router! :)
You can check that out here:
https://github.com/reactjs/react-router-tutorial/tree/master/lessons/04-nested-routes#sharing-our-navigation
Whenever you want to render a component route (the one you declared using </Route path="application-path" component={MyComponent} />), you need to specify where it will be placed. Using react-router, you specify this using the children prop. Then, whenever React "sees" this prop, it will render your routes (it can be a nested route too).
So, to fix your code, your App component needs to handle this.props.children correctly. Something like that:
class App extends React.Component {
/* ... */
render() {
return (
<div>
<header>Links go here</header>
{this.props.children}
</div>
)
}
}
Now, when you hit "/foo" route, this.props.children will be replaced by Foo component.
By the way, your nested routes (those inside ) don't need to have "/", since they will be "prepended". This is the way react-router render nested routes.
I think that is it, good luck with that! :)

TypeScript 1.6 error: JSX element type XXX does not have any construct or call signature

var CommentList = React.createClass({
render: function () {
return (
<div className="commentList">
Hello, world!I am a CommentList.
</div>
);
}
});
var CommentBox = React.createClass({
render: function () {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList /> //ERROR
</div>
);
}
});
React.render(
React.createElement(CommentBox, null),
document.getElementById('content')
);
With this code, I get the following error message:
JSX element type 'CommentList' does not have any construct or call signatures.
The same code works with plain HTML/JS (following this tutorial: https://facebook.github.io/react/docs/tutorial.html)
I have no clue why TypeScript doesn't like it.
Using Visual Studio 2013 with TS 1.6 (http://blogs.msdn.com/b/typescript/archive/2015/09/16/announcing-typescript-1-6.aspx)
It works fine without error (screen shot from atom-typescript) :
Suggestions:
Make sure visual studio is truly using typescript 1.6
Make sure you have react.d.ts included and try not to use the global version
Make sure you have the React variable available (e.g. import React = require('react');).

Resources