I am trying it integrate sorting and pagination in angular2 rc5. Pagination is working with ng2-pagination, searching for sorting. Any good example for sorting?
If anybody is still looking for answer (only for pagination), This link is a useful resource -
Implementing Pagination in angular2 > v.RC5
I integrated it within 5 minutes after I got above link.
In case - link is no longer available , here are the steps
app.module.ts
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {Ng2PaginationModule} from 'ng2-pagination'; // <-- import the module
imort {MyComponent} from './my.component';
#NgModule({
imports: [BrowserModule, Ng2PaginationModule], // <-- include it in your app module
declarations: [MyComponent],
bootstrap: [MyComponent]
})
export class MyAppModule {}
app.component.ts
import {Component} from '#angular/core';
#Component({
selector: 'my-component',
template: `
<ul>
<li *ngFor="let item of collection | paginate: { itemsPerPage: 10, currentPage: p }"> ... </li>
</ul>
<pagination-controls (pageChange)="p = $event"></pagination-controls>
`
})
export class MyComponent {
public collection: any[] = someArrayOfThings;
}
Therefor, For server side paging we can change this line of pagination-controls with replace some custom event -
This event (myCustomEvent($event)) must be defined and declared in component class or whatever you are going to use as a bootstrapper.
For sorting, excuse me for now.
Related
I'm using Vue with Laravel Mix. In Vue version 2, I was able to do this:
1. resources/js/app.js:
import Vue from 'vue';
import MyComponent from './MyComponent';
Vue.component('my-component', MyComponent);
2. resources/js/MyComponent.vue:
<template>
<p>{{message}}</p>
</template>
<script>
export default {
name: "MyComponent",
props: ['message']
}
</script>
As this Vue 2 document instructed. I know it was not the best practice, but it was the only approach that I have to conveniently pass data from Laravel's Blade template to the component, such as below:
3. anyview.blade.php:
<my-component :message='message' id='app'></my-component>
<script src='public/js/app.js'><script> //include compiled resources/js/app.js
<script>
let app = new Vue({
el: '#app',
data() {
return {
message: 'Hello World';
}
}
})
</script>
In real case, 'Hello World' would be replaced with something like:
message: {{$myMessaGe}}
But since Vue 3, Vue.component is no longer a thing because Vue object is not a default export.
This work flow (1-2-3) has been seamlessly fine, so returning to Vue2 is the last unhappy choice :(
I have tried to work around, just changing Vue.component with the new createApp:
4. resources/js/app.js:
import { createApp } from 'vue';
import MyComponent from './MyComponent';
createApp({
components: {
MyComponent,
}
}).mount('#app');
But instead of adding MyComponent to current instance, it just creates a new one as depicted below - meaning that the prop message can't be passed through.
My question is: Is there any alternative API or workaround to compensate the loss of Vue.component()?
I have only worked with Vue3 so far but what I understand from the documentation is that the components in Vue3 are not that different from components in Vue2.
Try this solution:
import { createApp } from 'vue';
import MyComponent from './MyComponent';
const app = createApp({});
app
.component('MyComponent', MyComponent)
.mount('#app');
You can find more about this in the Vue3 docs.
I want to show the edit link only for privileged users. I have user information that I am using for example for routing, and I can use it in components. However, I have not found any way to show/hide the edit link on each page based on the user roles. It must be done client side. Please help.
I found a way to do this:
Follow the instructions to extend the default theme.
Make your own EditLink component like this:
// EditLink.vue
<template></template>
<script setup>
import { onMounted } from "vue";
import { usePageFrontmatter } from "#vuepress/client";
onMounted(() => {
const fm = usePageFrontmatter();
fm.value.editLink = true; // Replace true with your logic
});
</script>
In the Layout component (see instructions linked above) do this:
// Layout.vue
<template>
<Layout>
<template #page-bottom> <EditLink /></template>
</Layout>
</template>
<script setup>
import Layout from "#vuepress/theme-default/lib/client/layouts/Layout.vue";
import EditLink from "../components/EditLink";
</script>
I need to import a vue js component page into another component by route name.
Anyone can show me the solution.
for example
{ path: '/dashboardadmin', component: require('./components/Dashboard.vue').default, name: 'AdminDashboard' }
this is one of my vue route. I have to import this component into another component by the name AdminDashboard
like this
import AdminDashboard from '*route name*';
Anyone can help me?
thanks in advance
if your parent component is A.vue and the component that you want to import in A.vue is like B.vue then you have to only import your B.vue into A.vue like this
import B from './B.vue' and use it into export default
export default {
components: {
B
},
}
simple
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! :)
In Angular 1 I have written a custom directive ("repeater-ready") to use with ng-repeat to invoke a callback method when the iteration has been completed:
if ($scope.$last === true)
{
$timeout(() =>
{
$scope.$parent.$parent.$eval(someCallbackMethod);
});
}
Usage in markup:
<li ng-repeat="item in vm.Items track by item.Identifier"
repeater-ready="vm.CallThisWhenNgRepeatHasFinished()">
How can I achieve a similar functionality with ngFor in Angular 2?
You can use #ViewChildren for that purpose
#Component({
selector: 'my-app',
template: `
<ul *ngIf="!isHidden">
<li #allTheseThings *ngFor="let i of items; let last = last">{{i}}</li>
</ul>
<br>
<button (click)="items.push('another')">Add Another</button>
<button (click)="isHidden = !isHidden">{{isHidden ? 'Show' : 'Hide'}}</button>
`,
})
export class App {
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
#ViewChildren('allTheseThings') things: QueryList<any>;
ngAfterViewInit() {
this.things.changes.subscribe(t => {
this.ngForRendred();
})
}
ngForRendred() {
console.log('NgFor is Rendered');
}
}
origional Answer is here
https://stackoverflow.com/a/37088348/5700401
You can use something like this (ngFor local variables):
<li *ngFor="#item in Items; #last = last" [ready]="last ? false : true">
Then you can Intercept input property changes with a setter
#Input()
set ready(isReady: boolean) {
if (isReady) someCallbackMethod();
}
For me works in Angular2 using Typescript.
<li *ngFor="let item in Items; let last = last">
...
<span *ngIf="last">{{ngForCallback()}}</span>
</li>
Then you can handle using this function
public ngForCallback() {
...
}
The solution is quite trivial. If you need to know when ngFor completes printing all the DOM elements to the browser window, do the following:
1. Add a placeholder
Add a placeholder for the content being printed:
<div *ngIf="!contentPrinted">Rendering content...</div>
2. Add a container
Create a container with display: none for the content. When all items are printed, do display: block. contentPrinted is a component flag property, which defaults to false:
<ul [class.visible]="contentPrinted">
...items
</ul>
3. Create a callback method
Add onContentPrinted() to the component, which disables itself after ngFor completes:
onContentPrinted() {
this.contentPrinted = true;
this.changeDetector.detectChanges();
}
And don't forget to use ChangeDetectorRef to avoid ExpressionChangedAfterItHasBeenCheckedError.
4. Use ngFor last value
Declare last variable on ngFor. Use it inside li to run a method when this item is the last one:
<li *ngFor="let item of items; let last = last">
...
<ng-container *ngIf="last && !contentPrinted">
{{ onContentPrinted() }}
</ng-container>
<li>
Use contentPrinted component flag property to run onContentPrinted() only once.
Use ng-container to make no impact on the layout.
Instead of [ready], use [attr.ready] like below
<li *ngFor="#item in Items; #last = last" [attr.ready]="last ? false : true">
I found in RC3 the accepted answer doesn't work. However, I have found a way to deal with this. For me, I need to know when ngFor has finished to run the MDL componentHandler to upgrade the components.
First you will need a directive.
upgradeComponents.directive.ts
import { Directive, ElementRef, Input } from '#angular/core';
declare var componentHandler : any;
#Directive({ selector: '[upgrade-components]' })
export class UpgradeComponentsDirective{
#Input('upgrade-components')
set upgradeComponents(upgrade : boolean){
if(upgrade) componentHandler.upgradeAllRegistered();
}
}
Next import this into your component and add it to the directives
import {UpgradeComponentsDirective} from './upgradeComponents.directive';
#Component({
templateUrl: 'templates/mytemplate.html',
directives: [UpgradeComponentsDirective]
})
Now in the HTML set the "upgrade-components" attribute to true.
<div *ngFor='let item of items;let last=last' [upgrade-components]="last ? true : false">
When this attribute is set to true, it will run the method under the #Input() declaration. In my case it runs componentHandler.upgradeAllRegistered(). However, it could be used for anything of your choosing. By binding to the 'last' property of the ngFor statement, this will run when it is finished.
You will not need to use [attr.upgrade-components] even though this is not a native attribute due to it now being a bonafide directive.
I write a demo for this issue. The theory is based on the accepted answer but this answer is not complete because the li should be a custom component which can accept a ready input.
I write a complete demo for this issue.
Define a new component:
import {Component, Input, OnInit} from '#angular/core';
#Component({
selector: 'app-li-ready',
templateUrl: './li-ready.component.html',
styleUrls: ['./li-ready.component.css']
})
export class LiReadyComponent implements OnInit {
items: string[] = [];
#Input() item;
constructor() { }
ngOnInit(): void {
console.log('LiReadyComponent');
}
#Input()
set ready(isReady: boolean) {
if (isReady) {
console.log('===isReady!');
}
}
}
template
{{item}}
usage in the app component
<app-li-ready *ngFor="let item of items; let last1 = last;" [ready]="last1" [item]="item"></app-li-ready>
You will see the log in the console will print all the item string and then print the isReady.
I haven't yet looked in depth of how ngFor renders elements under the hood. But from observation, I've noticed it often tends to evaluate expressions more than once per each item it's iterating.
This causes any typescript method call made when checking ngFor 'last' variable to get, sometimes, triggered more than once.
To guarantee a one call to your typescript method by ngFor when it properly finishes iterating through items, you need to add a small protection against the multiple expression re-evaluation that ngFor does under the hood.
Here is one way to do it (via a directive), hope it helps:
The directive code
import { Directive, OnDestroy, Input, AfterViewInit } from '#angular/core';
#Directive({
selector: '[callback]'
})
export class CallbackDirective implements AfterViewInit, OnDestroy {
is_init:boolean = false;
called:boolean = false;
#Input('callback') callback:()=>any;
constructor() { }
ngAfterViewInit():void{
this.is_init = true;
}
ngOnDestroy():void {
this.is_init = false;
this.called = false;
}
#Input('callback-condition')
set condition(value: any) {
if (value==false || this.called) return;
// in case callback-condition is set prior ngAfterViewInit is called
if (!this.is_init) {
setTimeout(()=>this.condition = value, 50);
return;
}
if (this.callback) {
this.callback();
this.called = true;
}
else console.error("callback is null");
}
}
After declaring the above directive in your module (assuming you know how to do so, if not, ask and I'll hopefully update this with a code snippet), here is how to use the directive with ngFor:
<li *ngFor="let item of some_list;let last = last;" [callback]="doSomething" [callback-condition]="last">{{item}}</li>
'doSomething' is the method name in your TypeScript file that you want to call when ngFor finishes iterating through items.
Note: 'doSomething' doesn't have brackets '()' here as we're just passing a reference to the typescript method and not actually calling it here.
And finally here is how 'doSomething' method looks like in your typescript file:
public doSomething=()=> {
console.log("triggered from the directive's parent component when ngFor finishes iterating");
}