good way to filter items from writable store to display in svelte? - svelte-3

Is there a better way to do this?
<script>
import recipeStore from '../../recipeStore';
export let id; /* I got this id from the url param */
</script>
<div>
{#each $recipeStore as recipe }
{#if recipe.id == id}
<p>{recipe.name}</p>
{/if}
{/each}
</div>
Thanks!

You can filter your store-data inside the script tag:
<script>
import {counts} from "./store.js"
let id=0;
let mycounts
const filt=(value)=>{
mycounts=$counts.filter(count => count.id == id);
console.log("mycounts: ",mycounts)
}
$: filt(id)
</script>
You can use $: to observe the change in a variable. In my example when id changes the filt(id) function is called.
Here is REPL: https://svelte.dev/repl/77f92f3d3ca149dfa5475035cbbffeb5?version=3.29.0

Related

svelte keep updating store var without clicking to update

My app automatically update $content value without me clicking on buttons. I know it is a simple question, but I can't find out why, I'm learning svelte.
App.svelte
<script>
import { content } from './store.js';
import Item from './Item.svelte';
$content = [{ id:0,obj: "Fell free to browse any category on top." }];
function addContent(value) {
$content = [{ id:0,obj: value}]
}
</script>
<li><button on:click={addContent("Home Page")}>Home</button></li>
<li><button on:click={addContent("Products Page")}>Products</button></li>
<div class="Content">
<p>Fell free to browse any category on top.</p>
{#each $content as item}
<p><svelte:component this={Item} objAttributes={item} /></p>
{/each}
</div>
store.js
import { writable } from 'svelte/store';
export let content = writable({});
Item.svelte
<script>
import { fade } from 'svelte/transition';
export let objAttributes = {};
</script>
<p transition:fade>
{objAttributes.obj}
{#if objAttributes.otherattrib}<em>{objAttributes.otherattrib}</em>{/if}
</p>
This is because your on:click events are defined wrongly.
The on:click takes as argument a function like this
<button on:click={functionGoesHere}>
or, if you want it inlined
<button on:click={() => { }>
What happens in your case is that you directly call a function and the result of this function will then be called when the button is clicked. You can see that in this example:
<script>
function createFn() {
return () => console.log('logging this')
}
</script>
<button on:click={createFn}>Click here</button>
in this example the function () => console.log('logging this') will be attached the button.
So to come back to your code, this is easily fixed by making it a function instead of a function call:
<li><button on:click={() => addContent("Home Page")}>Home</button></li>

cdkDropList how to bind/update data back to the array / source?

In this simple Stackbliz based on Angular's CDK drop-drag list, I use drop() event to check values of array movies. How do I build a two-way binding to capture the data value change back to the array?
[(cdkDropListData)]="movies" won't do it.
You are missing the DragDropModule import.
On the example site components/src/components-examples/cdk/drag-drop it's in index.ts.
main.ts
import './polyfills';
...
import { DragDropModule } from '#angular/cdk/drag-drop';
import {CdkDragDropCustomPlaceholderExample} from './app/cdk-drag-drop-custom-placeholder-example';
#NgModule({
imports: [
...
DragDropModule
],
...
})
export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
Binding input
Based on comments, you want to two-way-bind the inputs.
The following needs to be added, if you are using drag and drop, or not.
Banana-in-box on <input>
A trackBy function in the ngFor expression
Bind to movies[i] (it will not work binding to movie)
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
<div class="example-box"
*ngFor="let movie of movies; index as i; trackBy: trackByFn"
cdkDrag
>
<div class="example-custom-placeholder" *cdkDragPlaceholder></div>
<input type="text" [(ngModel)]="movies[i]"/>
</div>
</div>
export class CdkDragDropCustomPlaceholderExample {
...
drop(event: CdkDragDrop<string[]>) {
alert(`Before drop update: ${this.movies}`);
moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
alert(`After drop update: ${this.movies}`);
}
trackByFn(index: number, item: String) {
return index;
}
}
Stackblitz
I fire the alert before and after the drop update, take your pick.

Angular Dart 2 - querySelect returning null

I'm trying to set up a drag&drop component to upload multiple files. However, when I attempt to access elements on the DOM with the querySelector method, I end up with null.
I've tried to implement the AfterViewInit class to no avail. Here's my current dart code for the component:
import 'dart:html';
import 'package:dnd/dnd.dart';
import 'package:angular/angular.dart';
#Component(
selector: 'upload',
templateUrl: 'upload.html',
styleUrls: [
'upload.css'
]
)
class Upload implements AfterViewInit {
#override
void ngAfterViewInit() {
// TODO: implement ngOnInit
Draggable d = new Draggable(document.querySelectorAll('.page'), avatarHandler : new AvatarHandler.clone());
var del = document.querySelector('.upload');
print(del); //prints null
Dropzone dropzone = new Dropzone(document.querySelector('.upload')); //throws an error, as it doesn't expect null.
dropzone.onDrop.listen((DropzoneEvent event){
print(event);
});
}
}
Also, my upload.html file is as follows:
<div class="center-me page" uk-grid>
<div class="uk-align-center text-align-center">
<h2 class="text-align-center" >Upload a file</h2>
<div class="upload uk-placeholder uk-text-center">
<span uk-icon="icon: cloud-upload"></span>
<span class="uk-text-middle">Attach binaries by dropping them here or</span>
<div uk-form-custom>
<input type="file" multiple>
<span class="uk-link">selecting one</span>
</div>
</div>
<progress id="progressbar" class="uk-progress" value="0" max="100" hidden></progress>
</div>
</div>
Thanks in advance.
So this looks like it should work. I wouldn't actually suggest doing it this way as it will get any element with an upload class which if you reuse the component will be a lot.
I would suggest using the ViewChild syntax instead
class Upload implements AfterViewInit {
#ViewChild('upload')
void uploadElm(HtmlElement elm) {
Dropzone dropzone = new Dropzone(elm);
dropzone.onDrop.listen((DropzoneEvent event){
print(event);
});
}
}
In the template:
<div class="uk-placeholder uk-text-center" #upload>
That said you shouldn't be getting null from the querySelect, but from the code you have shown I'm not sure why.

How to get the url to insert as a data with Redux Form?

I was able to get the url in the attachment field but for the redux form it was empty, how is possible to pass the value of the url to the redux form? Below is the code and the screenshot:
<div className="FileUpload">
<Dropzone
onDrop={this.onImageDrop.bind(this)}
multiple={false}
accept="image/*">
<div>Drop an image or click to select a file to upload.</div>
</Dropzone>
</div>
<div className="form-group">
<label htmlFor="attachment">Attachment:</label><br />
<input className="form-control" focus placeholder="attachment" type="text" name="attachment" ref="attachment" value={this.state.uploadedFileCloudinaryUrl} />
{this.state.uploadedFileCloudinaryUrl === '' ? null :
<div>
<p>{this.state.uploadedFile.name}</p>
<img src={this.state.uploadedFileCloudinaryUrl} alt="" />
</div>}
</div>
<div className="ui small image">
<img src={this.props.workrequest.attachment} alt="" />
</div>
the url in the attachemnt field
The first one is using the React Dropzone to get the url but for the Redux Form it was empty. May I know how to do that to get the url inserts at Redux Form here? Thank you
import React from 'React';
import { connect } from 'react-redux';
import { change, reduxForm } from 'redux-form';
import Dropzone from 'react-dropzone';
class UploadForm extends React.Component {
onDrop = (accepted) => {
if (!accepted.length) return;
// start uploading
this.setState({ isUploading: true });
const formData = new FormData();
formData.append('file', accepted[0]);
axios.post('upload', formData).then(
(res) => {
this.props.dispatch(change('uploadForm', 'url', res.url));
this.setState({ isUploading: false });
},
() => {
this.setState({ isUploading: false });
}
);
};
render() {
return (
<form>
<Dropzone onDrop={this.onDrop} />
</form>
);
}
}
export default connect()(
reduxForm({
form: 'uploadForm',
initialValues: {
url: ''
}
})(UploadForm)
);
Please use this.
Actually, you must use Field component from Redux-form.
Other wise, you can change form values using dispatch and change action creator.
import { Field, change } from 'redux-form';
this.props.dispatch(change('uploadForm', 'url', this.state.url));

React onChange method not working in react_on_rails

I am trying to create a sample app based on react_on_rails gem. In my react code react inbuild function like onChange or onSubmit are not working.
My HelloWorldWidget Component looks like this.
...
constructor(props, context) {
super(props, context);
_.bindAll(this, 'handleChange');
}
handleChange(e) {
const name = e.target.value;
console.log(name);
//this.props.updateName(name);
}
render() {
const { name } = this.props;
return (
<div className="container">
<h3>
Hello, {name}!
</h3>
<input className="form-control input-sm col-sm-4" type="text" onChange={this.handleChange}/>
</div>
);
}
Also if I disable server side pre-render of my component in my views/hello_world/index.html.erb file then the component is not rendering on UI.
<%= react_component("HelloWorldApp", props: #hello_world_props , prerender: false) %>
Github Repo: react-on-rails-sample-app
I'm not sure where _.bindAll method came from but the orthodox way of binding handlers is with this syntax:
this.handleChange = this.handleChange.bind(this);
If you use arrow function you don't need to bind it to the class;
handleChange = (e) => {
const name = e.target.value;
console.log(name);
//this.props.updateName(name);
}
Try to use arrow functions like this:
onChange={(e) => this.handleChange(e)}

Resources