Angular (keyup) event not detecting only # symbol - html

Im trying to implement search bar using angular (keyup) event.And i have file name like
base #,
base $,
base 1,
base #,
base 2,
when i search base # or base $ or base 1 in the search bar it filters fine. but when i search base # it dont filter base # it filter all file name with base.
here is the code below which i have coded
My html:
<input type="search" class="form-control" placeholder="Search file" (keyup)="onSearch($event)" [(ngModel)]='searchKeywords'>
my js code:
onSearch(event: any) {
const keywords = event.target.value;
if (keywords && keywords.length > 2) {
const apiURL =`abc/thg/hjy?filter[file.name]=${keywords}`;
this.api.get(apiURL).subscribe((data: any) => {
console.log(data);
this.topics = data.list;
if (this.trigger) {
this.trigger.openMenu();
}
});
} else {
this.topics = [];
this.trigger.closeMenu();
}
}

Now I'm able to pass # .
onSearch(event: any) {
const keywords = event.target.value;
const params: any = {};
if (keywords && keywords.length > 2) {
params['filter[translations.title]'] = keywords;
const options = {
search: params
};
const apiURL = `abc/thg/hjy`;
this.api.get(apiURL, options).subscribe((data: any) => {
console.log(data);
this.topics = data.list;
if (this.trigger) {
this.trigger.openMenu();
}
});
} else {
this.topics = [];
this.trigger.closeMenu();
}
}

I notice that you have an missing in the HTML markup.
<input type="search" class="form-control" placeholder="Search file" (keyup)="onSearch($event)" [(ngModel)]="searchKeywords">
Then, in the .ts file:
onSearch(event: any) {
...
}

I think the value is getting set ok in apiURL in the line:
const apiURL =`abc/thg/hjy?filter[file.name]=${keywords}`;
I think the problem is the following line, where you are passing the # (hashtag) without URL encoding it.
Try swapping out the hashtag with %23 before you use it in the next line - your get request.
See: How to escape hash character in URL

Related

pass function to input onChange and then set it in state reactjs?

I just cannot figure out how to do this.
This function works to split the string of the input ID.
function func() {
// Original string
let str = urlInput.value
// Splitting up the string
let array = str.split(".com/");
let joined = array[0]+".com/embed/"+array[1];
document.write(joined);
console.log("function happened")
}
I am trying to pass it through onChange and then set it in state but the function isn't being passed onChange?
{
currentAccount ? (<textarea
placeholder={spotifyLink}
type="url"
id="urlInput"
onChange={e => {{func}; setMessageValue(e.target.value)}}/>) : null
}
What am I doing wrong? How do I pass the function and then setState after the function has split the user input string onChange?
You can make use of controlled components. With this approach, the input value is controlled by a state. It promotes single source of truth, you can read more here.
CODE -
function TextAreaComponent() {
const [messageValue, setMessageValue] = useState('');
const splitString = (str) => {
// Splitting up the string
let array = str.split(".com/");
let joined = array[0]+".com/embed/"+array[1];
return joined;
}
const handleOnChange = (event) => {
const { value } = event.target;
const splittedString = splitString(value);
setMessageValue(splittedString);
}
return (
<textarea
// placeholder={spotifyLink}
// id="urlInput"
type="url"
value={messageValue}
onChange={handleOnChange}
/>
);
}

How to interact with multiple webelments in testcafe using json file

I want to interact with multiple elements like multiple checkboxes radio buttons, buttons etc. I want to store the label/name of the elements into the json file. How can I interact with multiple elements using the name from Json file in testcafe
Take a look at the data-driven test example. It shows how to load data from a JSON file. You can use the loaded data in Selector expressions like Selector('button').withText(data.buttons[0]) to reference elements.
I don't know your particular use case, but speaking purely technically, you can easily do what you're asking:
Resources/names.json:
{
"buttons": [
"First Click",
"Second Click"
],
"checkboxes": [
"Choice1",
"Choice2"
]
}
then I can lod the file in a test file and work with the values:
import { getBaseUrl } from '../Helpers/baseUrl';
import { getEnv } from '../Helpers/env';
import Webelements from '../Objects/webelements'
const baseUrl = getBaseUrl();
const env = getEnv();
const webelements = require('../Resources/names.json');
fixture `Webelements`
.page(baseUrl);
test
('Access Webelements From Json', async t => {
webelements.buttons.forEach((button) => {
console.log(button);
});
webelements.checkboxes.forEach((checkbox) => {
console.log(checkbox)
});
});
this will print the following into the console:
First Click
Second Click
Choice1
Choice2
Another solution could be using classes:
Objects/webelements.js:
class Checkboxes {
constructor () {
this.choices = {
1: "Choice1",
2: "Choice2"
}
}
}
class Buttons {
constructor () {
this.names = ["First Click", "Second Click"]
}
}
class Webelements {
constructor () {
this.checkboxes = new Checkboxes();
this.buttons = new Buttons();
}
}
export default new Webelements();
and use it like this:
test
('Access Webelements From Classes', async t => {
Object.entries(Webelements.checkboxes.choices).forEach(([key, val]) => {
console.log(key + " - " + val);
})
Webelements.buttons.names.forEach((name) => {
console.log(name)
});
});
this will output:
1 - Choice1
2 - Choice2
First Click
Second Click
So, there're options, but the point is that some solutions are better for some situations. I have very little idea about your situation, so you have to make this decision for yourself.

How to access ag-Grid API in React function component (useState hook)?

What is the best way of accessing ag-Grid API inside of React function component?
I have to use some of the methods from API (getSelectedNodes, setColumnDefs etc.) so I save a reference to the API (using useState hook) in onGridReady event handler:
onGridReady={params => {
setGridApi(params.api);
}}
and then I can call the API like this: gridApi.getSelectedNodes()
I haven't noticed any problems with this approach, but I'm wondering if there's more idiomatic way?
Stack:
ag-grid-community & ag-grid-react 22.1.1
react 16.12.0
We find the most idiomatic way to use a ref. As the api is not a state of our component. It is actually possible to simply do:
<AgGridReact ref={grid}/>
and then use it with
grid.current.api
Here an example:
import React, { useRef } from 'react'
import { AgGridReact } from 'ag-grid-react'
import { AgGridReact as AgGridReactType } from 'ag-grid-react/lib/agGridReact'
const ShopList = () => {
const grid = useRef<AgGridReactType>(null)
...
return (
<AgGridReact ref={grid} columnDefs={columnDefs} rowData={shops} />
)
}
The good thing here is, that you will have access to the gridApi but als to to the columnApi. Simply like this:
// rendering menu to show/hide columns:
{columnDefs.map(columnDef =>
<>
<input
type='checkbox'
checked={
grid.current
? grid.current.columnApi.getColumn(columnDef.field).isVisible()
: !(columnDef as { hide: boolean }).hide
}
onChange={() => {
if (grid.current?.api) {
const col = grid.current.columnApi.getColumn(columnDef.field)
grid.current.columnApi.setColumnVisible(columnDef.field, !col.isVisible())
grid.current.api.sizeColumnsToFit()
setForceUpdate(x => ++x)
}
}}
/>
<span>{columnDef.headerName}</span>
</>
)}
Well I am doing it in my project. You can use useRef hook to store gridApi.
const gridApi = useRef();
const onGridReady = params => {
gridApi.current = params.api; // <== this is how you save it
const datasource = getServerDataSource(
gridApi.current,
{
size: AppConstants.PAGE_SIZE,
url: baseUrl,
defaultFilter: props.defaultFilter
}
);
gridApi.current.setServerSideDatasource(datasource); // <== this is how you use it
};
I'm running into the same issue but here is a workaround that at least can get you the selected rows. Essentially what I'm doing is sending the api from the agGrid callbacks to another function. Specifically I use OnSelectionChanged callback to grab the current row node. Example below:
const onSelectionChanged = params => {
setDetails(params.api.getSelectedRows());
};
return (<AgGridReact
columnDefs={agData.columnDefs}
rowSelection={'single'}
enableCellTextSelection={true}
defaultColDef={{
resizable: true,
}}
rowHeight={50}
rowData={agData.rowData}
onCellFocused={function(params) {
if (params.rowIndex != null) {
let nNode = params.api.getDisplayedRowAtIndex(params.rowIndex);
nNode.setSelected(true, true);
}
}}
onSelectionChanged={function(params) {
onSelectionChanged(params);
params.api.sizeColumnsToFit();
}}
onGridReady={function(params) {
let gridApi = params.api;
gridApi.sizeColumnsToFit();
}}
deltaRowDataMode={true}
getRowNodeId={function(data) {
return data.id;
}}
/>);

Too tidious hooks when querying in REST. Any ideas?

I've just started using feathers to build REST server. I need your help for querying tips. Document says
When used via REST URLs all query values are strings. Depending on the service the values in params.query might have to be converted to the right type in a before hook. (https://docs.feathersjs.com/api/databases/querying.html)
, which puzzles me. find({query: {value: 1} }) does mean value === "1" not value === 1 ? Here is example client side code which puzzles me:
const feathers = require('#feathersjs/feathers')
const fetch = require('node-fetch')
const restCli = require('#feathersjs/rest-client')
const rest = restCli('http://localhost:8888')
const app = feathers().configure(rest.fetch(fetch))
async function main () {
const Items = app.service('myitems')
await Items.create( {name:'one', value:1} )
//works fine. returns [ { name: 'one', value: 1, id: 0 } ]
console.log(await Items.find({query:{ name:"one" }}))
//wow! no data returned. []
console.log(await Items.find({query:{ value:1 }})) // []
}
main()
Server side code is here:
const express = require('#feathersjs/express')
const feathers = require('#feathersjs/feathers')
const memory = require('feathers-memory')
const app = express(feathers())
.configure(express.rest())
.use(express.json())
.use(express.errorHandler())
.use('myitems', memory())
app.listen(8888)
.on('listening',()=>console.log('listen on 8888'))
I've made hooks, which works all fine but it is too tidious and I think I missed something. Any ideas?
Hook code:
app.service('myitems').hooks({
before: { find: async (context) => {
const value = context.params.query.value
if (value) context.params.query.value = parseInt(value)
return context
}
}
})
This behaviour depends on the database and ORM you are using. Some that have a schema (like feathers-mongoose, feathers-sequelize and feathers-knex), will convert values like that automatically.
Feathers itself does not know about your data format and most adapters (like the feathers-memory you are using here) do a strict comparison so they will have to be converted. The usual way to deal with this is to create some reusable hooks (instead of one for each field) like this:
const queryToNumber = (...fields) => {
return context => {
const { params: { query = {} } } = context;
fields.forEach(field => {
const value = query[field];
if(value) {
query[field] = parseInt(value, 10)
}
});
}
}
app.service('myitems').hooks({
before: {
find: [
queryToNumber('age', 'value')
]
}
});
Or using something like JSON schema e.g. through the validateSchema common hook.

Angular Firebase Storage, Assigning User Input Properties to Real Time Database

I want to upload a file especially an image to my firebase storage. I found a tutorial from this link. I added the more properties like url and file to my existing class and i followed the function template on that link. But apparently i did something wrong. The file uploaded to my storage and the console log didn't return any error. I need help with assigning another properties like prdName, prdCategory, and prdSup with user input correctly. Can someone help me with this please?
//product.ts
export class Product {
$prdKey: string;
prdName: string;
prdCategory: string; //Category
prdSup: string; //supplier
prdDescription: string;
prdImage: string; //name
prdUrl: string; //url
file: File;
constructor(file: File) {
this.file = file;
}
}
//service.ts
variable: any;
selectedProduct: Product = new Product(this.variable); //-->there was an error here that said expected 1 argument but got 0 so i add variable:any;
private basePath = '/product';
pushFileToStorage(Product: Product, progress: {
percentage: number
}) {
const storageRef = firebase.storage().ref();
const uploadTask = storageRef.child(`${this.basePath}/${Product.file.name}`).put(Product.file);
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
// in progress
const snap = snapshot as firebase.storage.UploadTaskSnapshot
progress.percentage = Math.round((snap.bytesTransferred / snap.totalBytes) * 100)
},
(error) => {
// fail
console.log(error)
},
() => {
// success
/*--What should i assign here?--*/
Product.prdName = Product.file.name,
Product.prdCategory = Product.file.name,
Product.prdSup = Product.file.name,
Product.prdDescription = Product.file.name,
/*------------------------------------------*/
Product.prdUrl = uploadTask.snapshot.downloadURL,
Product.prdImage = Product.file.name,
this.saveFileData(Product)
}
);
}
private saveFileData(Product: Product) {
this.firebase.list(`${this.basePath}/`).push(Product);
}
//component.ts
upload() {
const file = this.selectedFiles.item(0);
this.currentFileUpload = new Product(file);
this.ProductService.pushFileToStorage(this.currentFileUpload, this.progress);
}
<!--component.html-->
<!--form snippet-->
<form #productForm="ngForm" (ngSubmit)="upload()">
<div class="form-group">
<label>Product Name</label>
<input class="form-control" name="prdName" #prdName="ngModel" [(ngModel)]="ProductService.selectedProduct.prdName">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Please let me know if more snippets are needed. Thank you in advance.
(Update)
I put the push function inside //success condition, however i'm not sure what to assign for each class properties. Product.prdName = Product.file.name, will give me prdName equal to the file name. I tried Product.prdName = selectedProduct.prdName, but looks like it is not correct.
I figured it out, it should looks like this, works for me :D
() => {
// success
this.productList.push({
prdName: this.selectedProduct.prdName,
prdCategory: this.selectedProduct.prdCategory,
prdSup: this.selectedProduct.prdSup,
prdDescription: this.selectedProduct.prdDescription,
prdUrl: this.selectedProduct.prdUrl = uploadTask.snapshot.downloadURL,
prdImage: this.selectedProduct.prdImage = Product.file.name,
})
this.saveFileData(Product)
}