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

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.

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>

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

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

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.

What does '...' in React-Native mean?

A piece of react-native code:
enderScene(route, navigator) {
let Component = route.component;
return (
<Component {...route.params} navigator={navigator}></Component>
);
}
this code returns a Component Object ,
But I don't understand this code ---> {...route.params}
Question:
What is meant by '...' ?
Can you tell me what is meant by " {...route.params}" ?
The '...' is called Spread syntax.
The spread syntax allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) or multiple variables (for destructuring assignment) are expected.
Example :
var car = ["door", "motor", "wheels"];
var truck = [...car, "something", "biggerthancar"];
// truck = ["door", "motor", "wheels", "something", "biggerthancar"]
If you want to know more about spread operator :
https://rainsoft.io/how-three-dots-changed-javascript/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
To expand on the above, in the context of the original post the spread operator is essentially passing through all of the parameters in route.params
For example if route.params was the object
{key: 'my-route', title: 'My Route Title'}
Then
<Component {...route.params} navigator={navigator} />
Could be re-written as
<Component key={route.params.key} title={route.params.title} navigator={navigator} />
The other "side" of this is the destructuring assignment (example using stateless react components)
const Component = (props) => {
// this is simply referencing the property by the object key
let myKey = props.key
// this is using destructuring and results in the variables key, title and navigator which are from props.key, props.title and props.navigator
let { key, title, navigator } = props
return <Text>{title}</Text>
}
You can also do this in the function declaration like so which achieves the same thing
const Component = ({key, title, navigator}) => {
// now you have variables key, title and navigator
return <Text>{title}</Text>
}
See Destructuring
Ok, I was confused about that for a long period of time.
So, I'll try my best to explain it to you:
Suppose, you've a react class like bellow:
import React, {Component} from 'react';
import { Link } from 'react-router-dom';
class SingleService extends Component{
render(){
return(
<div class="col-md-4">
<span class="fa-stack fa-4x">
<i class="fas fa-circle fa-stack-2x text-primary"></i>
<i class={`fas ${this.props.icon} fa-stack-1x fa-inverse`}></i>
</span>
<h4 class="service-heading">{this.props.title}</h4>
<p class="text-muted">{this.props.description}</p>
</div>
);
}
}
export default SingleService;
Here, you can see that there are so many {this.props.variable}.
Those are used to create dynamic values when we import this above class into another class, like bellow:
import React, {Component} from 'react';
import { Link } from 'react-router-dom';
import SingleService from './SingleService';
// declaring a constant array to hold all of our services props.
// The following array is made up of the objects.
const services = [
{
title:'E-commerce',
description:'Description text on E-commerce',
icon: 'fa-shopping-cart'
}
];
class Services extends Component{
render(){
return(
<div>
<section class="page-section" id="services">
<div class="container">
<div class="row">
<div class="col-lg-12 text-center">
<h2 class="section-heading text-uppercase">Services</h2>
<h3 class="section-subheading text-muted">Lorem ipsum dolor sit amet consectetur.</h3>
</div>
</div>
<div class="row text-center">
{/* it's looping through an object, that's why we've used key value pair. */}
{ /*
to write js inside JSX, we use curly braces
here we're using array.map() function.
*/}
{services.map((service, index) => {
// returning our component with props.
// return (<SingleService title={service.title} description={service.description} icon={service.icon} />);
// or, we can write the following
return (<SingleService {...service}/>);
})}
</div>
</div>
</section>
</div>
);
}
}
export default Services;
Now, here, I've used the famous
return (<SingleService {...SingleService}/>);
But one very important thing, I could avoid using it simply by writing the following line:
return (<SingleService title={service.title} description={service.description} icon={service.icon} />);
So, you can see in the send return statement, I've specified all of the props variables individually and assigned values to those, whereas in the first return statement, I've passed in all pf the props together from the SingleService object at once, that will pass all od the key-value pairs.
To add to the above given answers, the ... or the spread operator is not something special to react native. It is a feature in es6. ES6 stands for ecma script and is the standard followed for javascript. This means that you could create a .js file outside of react/react-native and run it in a node env and the spread operator would still work.

Angular Dart: Data binding doesn't work when manipulating the controller from the outside, part two

A short background:
This example is a slightly more complicated version of my Angular Dart: Data binding doesn't work when manipulating the controller from the outside question that has been answered correctly. I only added a toggleable "show resolved comments" link to this version. Even though I initialized every variable to non-null values the problem still happens.
Full description of the actual problem:
I have two controllers nested into each other. The outer controller shows/hides the inner controller by using an ng-switch directive.
The outer controller also contains a checkbox. If this checkbox gets checked then the inner controller is made visible (via the above ng-switch directive). This checkbox works as intended.
There's also an "open" link outside the controllers. Its onclick handler calls into the outer controller and is supposed to check the checkbox via the model. The problem is that even though the model gets changed, the view doesn't get updated, unless I explicitly call scope.apply(), which I shouldn't. Even if I remove the comment before scope.apply() in my code then data binding doesn't work within InnerController.
This pattern has worked flawlessly in AngularJS but apparently doesn't in AngularDart.
I insist to this pattern or something similar because I'm in the process of integrating AngularDart into a legacy application that doesn't use data binding so I have to trigger model changes from outside the models.
Thanks in advance!
<html ng-app>
<head>
<title>Angular.dart nested controllers</title>
</head>
<body>
open
<div outer-controller ng-switch="outerCtrl.showInnerController">
<input type="checkbox" ng-model="outerCtrl.showInnerController">
<div inner-controller ng-switch-when="true">
Your name: <input ng-model="innerCtrl.yourName">
<br>
Hello {{innerCtrl.yourName}}!
<div ng-switch="innerCtrl.showResolvedComments" style="text-decoration:underline; color:blue; cursor:pointer">
<div ng-switch-when="true" ng-click="innerCtrl.showResolvedComments = false">Hide resolved comments</div>
<div ng-switch-when="false" ng-click="innerCtrl.showResolvedComments = true">Show resolved comments</div>
</div>
</div>
<div inner-controller ng-switch-when="false">
other controller
</div>
</div>
<script type="application/dart">
import "dart:html";
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
OuterController outerController;
#Controller(selector:'[outer-controller]', publishAs:'outerCtrl')
class OuterController {
bool showInnerController = false;
Scope scope;
OuterController(this.scope) {
outerController = this;
}
void showOuterController() {
showInnerController = true;
//scope.apply();
}
}
#Controller(selector:'[inner-controller]', publishAs:'innerCtrl')
class InnerController {
String yourName = 'defaultName';
bool showResolvedComments = true;
}
class MyAppModule extends Module {
MyAppModule() {
type(InnerController);
type(OuterController);
}
}
main() {
applicationFactory().addModule(new MyAppModule()).run();
querySelector('#open').onClick.listen((Event event) {
outerController.showOuterController();
});
}
</script>
</body>
</html>
After some experimentation, it's look like angular listen specified event to activate ng-model, and it doesn't look every variable change, i think because it's complicated to watch every change in variable without impact performance.
You can change your approach by simulate a user click on the check box
like:
CheckboxInputElement checkBox = querySelector("input");
if (checkBox.checked == false) {
checkBox.click();
}
It's maybe not the cleaner way to do this, but it works
Here the full code with the patch
<html ng-app>
<head>
<title>Angular.dart nested controllers</title>
</head>
<body>
open
<div outer-controller ng-switch="outerCtrl.showInnerController">
<input type="checkbox" ng-model="outerCtrl.showInnerController">
<div inner-controller ng-switch-when="true">
Your name: <input ng-model="innerCtrl.yourName">
<br>
Hello {{innerCtrl.yourName}}!
<div ng-switch="innerCtrl.showResolvedComments" style="text-decoration:underline; color:blue; cursor:pointer">
<div ng-switch-when="true" ng-click="innerCtrl.showResolvedComments = false">Hide resolved comments</div>
<div ng-switch-when="false" ng-click="innerCtrl.showResolvedComments = true">Show resolved comments</div>
</div>
</div>
<div inner-controller ng-switch-when="false">
other controller
</div>
</div>
<script type="application/dart">
import "dart:html";
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
OuterController outerController;
#Controller(selector:'[outer-controller]', publishAs:'outerCtrl')
class OuterController {
bool showInnerController = false;
Scope scope;
OuterController(this.scope) {
outerController = this;
}
void showOuterController() {
showInnerController = true;
print("showOuterController");
//scope.apply();
}
}
#Controller(selector:'[inner-controller]', publishAs:'innerCtrl')
class InnerController {
String yourName = 'defaultName';
bool showResolvedComments = true;
}
class MyAppModule extends Module {
MyAppModule() {
type(InnerController);
type(OuterController);
}
}
main() {
applicationFactory().addModule(new MyAppModule()).run();
querySelector('#open').onClick.listen((Event event) {
outerController.showOuterController();
// Added Code
CheckboxInputElement checkBox = querySelector("input");
if (checkBox.checked == false) {
checkBox.click();
}
// End added code
});
}
</script>
</body>
</html>

Resources