material2 process bar implementation issue - angular-material2

I want to implement this process bar in my web application, but on the basis of http request cannot be work.
[https://material.angular.io/components/progress-bar/overview][1]
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-process-bar',
templateUrl: './process-bar.component.html',
styleUrls: ['./process-bar.component.css']
})
export class ProcessBarComponent{
color: string = 'accent';
determinateProgressValue: number = 10;
}
.process-bar-custom-css{
margin: 0px;
z-index: 9999;
}
<mat-progress-bar
class="process-bar-custom-css"
mode="determinate"
[value]="determinateProgressValue"
[color]="color">
</mat-progress-bar>

Example :
<div ng-show="isLoading">
<i class="fa fa-spinner fa-spin fa-3x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
.controller('firstCtrl', ['$scope', '$http', 'ngProgressFactory', function ($scope, $http, ngProgressFactory) {
$scope.isLoading = null;
$http.get('https://feeds.citibikenyc.com/stations/stations.json').
success(function (data, status, headers, config) {
$scope.isLoading = 'done';
$scope.data = data; //first get the full object
$scope.mainArray = data.stationBeanList;
$timeout($scope.progressbar.complete(), 100);
}).
error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}]);

Related

retrieving and storing Events in database to and from FullCalendar 5 with laravel 9, Vue 3, Breeze, Inertia, and Ziggy

I'm having quite a tussle with my code. I've deployed FullCalendar v5 as a Vue 3 component inside a laravel 9 site using Breeze for authentication and Inertia for speedy rendering. I have the Calendar/Pages/Index.vue displaying the calendar and updating events on the calendar with modals from the example, but I cannot manage to get the modals to create events in the database, nor get the events from the database table to display on the calendar. I'm trying to avoid Ajax and use axios to retrieve a JSON feed.
Here's the part of my controller that creates the JSON feed:
public function showEvents(Request $request) {
$event = Event::get(['title','acronym','city','venue','value','start','end']);
return response()->json(["events" => $event]);
}
Here's what the JSON feed returns:
{"events":[{"title":"Test","acronym":"TST","city":"Denver","venue":"Big Venue","value":"$0","start":"2022-10-25 00:00:00","end":"2022-10-28 00:00:00"}]}
And here's my rather massive Calendar/Index.vue:
<template>
<head title="Dashboard" />
<BreezeAuthenticatedLayout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Resource Calendar Timeline
</h2>
</template>
<div class="py-12">
<div class="max-w-10xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-12 bg-white border-b border-gray-200">
<!--start calendar-->
<div class='demo-app'>
<div class='demo-app-main'>
<FullCalendar
class='demo-app-calendar'
:events="calendarEvents"
:options='calendarOptions'>
<template v-slot:eventContent='arg'>
<b>{{ arg.timeText }}</b>
<i>{{ arg.event.title }}</i>
</template>
</FullCalendar>
</div>
</div>
<!--end calendar-->
</div>
</div>
</div>
</div>
</BreezeAuthenticatedLayout>
</template>
<!--start calendar-->
<script setup lang='ts'>
import BreezeAuthenticatedLayout from '#/Layouts/AuthenticatedLayout.vue';
import { head, Link } from '#inertiajs/inertia-vue3';
import '#fullcalendar/core/vdom'; // solves problem with Vite
import { defineComponent } from 'vue';
import FullCalendar, { CalendarOptions, EventApi, DateSelectArg, EventClickArg } from '#fullcalendar/vue3';
import dayGridPlugin from '#fullcalendar/daygrid';
import timeGridPlugin from '#fullcalendar/timegrid';
import listPlugin from '#fullcalendar/list';
import interactionPlugin from '#fullcalendar/interaction';
import axios from 'axios';
</script>
<script lang='ts'>
const Demo = defineComponent({
components: {
FullCalendar,
},
data() {
return {
// trying to pull events from DB json -->>
eventSources: [{
url: 'https://l9-v3-breeze-crud.ddev.site/show-events', // use the `url` property
color: 'yellow', // an option!
textColor: 'black' // an option!
}],
calendarEvents: [{
events(title, start, end, callback) {
axios.get('https://l9-v3-breeze-crud.ddev.site/show-events').then(res => {
callback(res.data.events)
})
},
failure: function() {
alert('there was an error while fetching events!');
},
color: 'red',
textColor: 'white',
}],
//end events pull from DB -->
calendarOptions: {
plugins: [
dayGridPlugin,
timeGridPlugin,
listPlugin,
interactionPlugin // needed for dateClick
],
headerToolbar: {
left: 'promptResource prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
},
},
initialView: 'dayGridMonth',
events: this.getEvents,
editable: true,
selectable: true,
selectMirror: true,
dayMaxEvents: true,
weekends: true,
select: this.handleDateSelect,
eventClick: this.handleEventClick,
eventsSet: this.handleEvents
} as CalendarOptions,
currentEvents: [] as EventApi[],
}
},
methods: {
getEvents(info, successCallback, failureCallback) {
events(start, end, timezone, callback) {
axios.get('http://localhost:8000/show-events').then(res => {
callback(res.data.eventList)
})
})
},
handleWeekendsToggle() {
this.calendarOptions.weekends = !this.calendarOptions.weekends // update a property
},
handleDateSelect(selectInfo: DateSelectArg) {
let title = prompt('Please enter a new title for your event')
let calendarApi = selectInfo.view.calendar
calendarApi.unselect() // clear date selection
if (title) {
calendarApi.addEvent({
id: createEventId(),
title,
start: selectInfo.startStr,
end: selectInfo.endStr,
allDay: selectInfo.allDay
})
}
},
handleEventClick(clickInfo: EventClickArg) {
if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) {
clickInfo.event.remove()
}
},
handleEvents(events: EventApi[]) {
this.currentEvents = events
},
}
})
export default Demo
</script>
<style lang='css'>
h2 {
margin: 0;
font-size: 16px;
}
ul {
margin: 0;
padding: 0 0 0 1.5em;
}
li {
margin: 1.5em 0;
padding: 0;
}
b { /* used for event dates/times */
margin-right: 3px;
}
.demo-app {
display: flex;
min-height: 100%;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
}
.demo-app-sidebar {
width: 300px;
line-height: 1.5;
background: #eaf9ff;
border-right: 1px solid #d3e2e8;
}
.demo-app-sidebar-section {
padding: 2em;
}
.demo-app-main {
flex-grow: 1;
padding: 3em;
}
.fc { /* the calendar root */
max-width: 1200px;
margin: 0 auto;
}
.fc-day-today
{
background-color: var(--fc-today-bg-color, rgba(255, 220, 40, 0.15));
}
.fc-day-sat, .fc-day-sun
{
background-color: var(--fc-today-bg-color, rgba(255, 100, 40, 0.15));
}
</style>
I'm stumped! Either I pull an empty array for events with
events[]
or I get a 500 error denoting that "Module source URI is not allowed in this document: “http://[::1]:5173/resources/js/Pages/Calendar/Index.vue" when I try the axios.get URL
and, not matter what I try, I can't seem to get it to pull the 'calendarEvents' options from
calendarEvents: [{
events(title, start, end, callback) {
axios.get('https://l9-v3-breeze-crud.ddev.site/show-events').then(res => {
callback(res.data.events)
})
},
failure: function() {
alert('there was an error while fetching events!');
},
color: 'red',
textColor: 'white',
}],
Additional Information:
I've been continuing to look for a solution and found several online demo's that resolve the issue at hand, but none with my particular project dependencies. Being a newbie at this, I'm just not certain on how to merge the code. In particular, the structure of the Calendar/Index.vue file taken from the http://fullcalendar.io Vue3 and TypeScript demo here https://github.com/fullcalendar/fullcalendar-example-projects/tree/master/vue3-typescript And in the app.js file from this demo https://www.positronx.io/how-to-display-events-in-calendar-with-laravel-vue-js/
My app.js is complicated by the installation of Ziggy and Inertia and I'm not certain how to construct the Vue rather than a blade. Here's my app.js:
import './bootstrap';
import '../css/app.css';
//import { ZiggyVue } from 'ziggy-vue';
//import route from 'ziggy';
import { createApp, h } from 'vue';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { createInertiaApp } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use(ZiggyVue, Ziggy)
.mount(el);
},
});
InertiaProgress.init({ color: '#4B5563' });
Ok, I figured out how to use axios to retrieve events from the JSON feed. The issue wasn't in the app.js routes, but rather in the actual Vue component itself.
Previously unmentioned, here is the route that constructs the JSON feed of events:
Route::get('show-events', [CalendarController::class, 'showEvents']);
Here's the part of my controller that generates that JSON feed for events from the database:
public function showEvents(Request $request) {
$event = Event::get(['title','acronym','city','venue','value','start','end']);
return response()->json(["events" => $event]);
And here's the method part of the Vue component that retrieves events from the JSON feel and publishes them to the calendar:
methods: {
getEvents() {
axios.get('show-events')
.then(response => {
this.calendarOptions.events = response.data.events;
});
},

cannot find particular movie in a list vue and laravel

I am trying to get the details of a particular movie in a list of movies but it cannot get the particular id.
here is my Vue component:
<template>
<div>
<el-row :gutter="10">
<el-col :span="6" v-for="movie in movies" v-bind:key="movie">
<el-card shadow="always" :body-style="{ padding: '0px'} ">
<img v-bind:src="movie.cover_photo" class="image">
<div style="padding: 14px;">
<div class="bottom clearfix">
{{movie.title}}
<h4>{{ movie.year }}</h4>
<h4>{{ movie.type }}</h4>
</div>
<div class="block">
<el-rate v-model="value1" :max="10"></el-rate>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
movies: [],
movie: {
id: '',
}
};
},
created() {
this.fetchMovieList();
},
methods: {
fetchMovieList() {
axios.get('/movies').then(response => {
this.movies = response.data;
})
.catch(error => console.log(error))
},
showMovie(id) {
axios.get('/movies/' + id).then((res) => {
if (res.data.status == true) {
this.movie = res.data.movie;
console.log(res.data.movie)
} else {
alert('No Movie founded with this id')
}
}).catch((err) => {
alert('error')
})
}
}
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>
my show method:
public function show($id)
{
$movie=Movie::find($id);
if($movie){
return response()->json(['status'=>true,'movie'=>$movie]);
}else{
return response()->json(['status'=>false]);
}
}
and my route:
Route::get('/movies/{id}', 'MoviesController#show');
It cannot find the movie with the particular id. What could be wrong? When I visit the API URL directly on the browser and directly type the route I get the particular movie I want.
Not sure if this would resolve all your issues but you could try the following:
Route::get('/movies/{movie}', 'MoviesController#show');
public function show(Movie $movie)
{
return view('details', ['movie' => $movie]);
}
Also, the naming convention for controllers is to use the model name in its singular form. Your controller should therefore be named MovieController without s.
Another thing, in your view component you should include the movie_id in the url otherwise Laravel has no way to know which movie you're trying to fetch:
...
axios.get('/movies/1')
...

React MovieDB API problem. Setting this.setState twice breaks my component

I followed a youtube tutorial using the MovieDB API with React. I can search for movies and pull up a title, description, and movie image. I want to add the ability for a youtube trailer to be played. I have successfully fetched the youtube ID's and store them. I'm having trouble displaying them. If I uncomment in my App.js
this.setState({ rows: videoRows });
Then the youtube videos work. But my title, description, and movie image are undefined and vice versa.
App.js
import React, { Component } from "react";
import "./App.css";
import MovieRow from "./MovieRow.js";
import $ from "jquery";
class App extends Component {
constructor(props) {
super(props);
this.state = {};
this.performSearch("woman");
}
performSearch(searchTerm) {
// console.log("perform search");
const API_KEY = "625914798003ef54176364f32c232968";
const urlString = `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${searchTerm}`;
const urlVideoString = `https://api.themoviedb.org/3/movie/297762/videos?api_key=${API_KEY}&language=en-US`;
//fetch generic info
$.ajax({
url: urlString,
success: searchResults => {
console.log("fetch basic success");
const results = searchResults.results;
var videoRows = [];
var movieRows = [];
// call next ajax function
$.ajax({
url: urlVideoString,
success: searchResults => {
console.log("fetch Youtube video key success");
const results = searchResults.results;
results.forEach(movie => {
movie.video_src = movie.key;
console.log(movie.video_src);
var videoRow = <MovieRow key={movie.id} movie={movie} />;
videoRows.push(videoRow);
});
//If I run this line below it will break
//my generic basic info(title, movie description, and picture) ,
//but it makes the youtube player work
// this.setState({ rows: videoRows });
},
error: (xhr, status, err) => {
console.log("failed video fetch");
}
});
results.forEach(movie => {
movie.poster_src =
"https://image.tmdb.org/t/p/w185" + movie.poster_path;
console.log(movie.poster_path);
const movieRow = <MovieRow key={movie.id} movie={movie} />;
movieRows.push(movieRow);
});
this.setState({ rows: movieRows });
},
error: (xhr, status, err) => {
console.log("failed fetch");
}
});
}
searchChangeHandler(event) {
console.log(event.target.value);
const boundObject = this;
const searchTerm = event.target.value;
boundObject.performSearch(searchTerm);
}
render() {
return (
<div>
<table className="titleBar">
<tbody>
<tr>
<td>
<img alt="app icon" width="100" src="green_app_icon.svg" />
</td>
<td width="8" />
<td>
<h1>MoviesDB Search</h1>
</td>
</tr>
</tbody>
</table>
<input
style={{
fontSize: 24,
display: "block",
width: "99%",
paddingTop: 8,
paddingBottom: 8,
paddingLeft: 16
}}
onChange={this.searchChangeHandler.bind(this)}
placeholder="Search for movie by title..."
/>
{this.state.rows}
</div>
);
}
}
export default App;
MovieRow.js
import React from "react";
import YouTube from "react-youtube";
class MovieRow extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
viewMovie() {
const url = "https://www.themoviedb.org/movie/" + this.props.movie.id;
window.location.href = url;
}
viewTrailer() {
//const trailerURL = "https://www.youtube.com/watch?v=1Q8fG0TtVAY";
}
_onReady(event) {
// access to player in all event handlers via event.target
event.target.pauseVideo();
}
render() {
const opts = {
height: "390",
width: "50%",
playerVars: {
// https://developers.google.com/youtube/player_parameters
autoplay: 1
}
};
return (
<table key={this.props.movie.id}>
<tbody>
<tr>
<td>
<img alt="poster" width="180" src={this.props.movie.poster_src} />
</td>
<td>
<h1>src {this.props.movie.video_src}</h1>
<h3>{this.props.movie.title}</h3>
<p>{this.props.movie.overview}</p>
<YouTube
videoId={this.props.movie.video_src}
opts={opts}
onReady={this._onReady}
/>
<input
className="btn btn-primary"
type="button"
onClick={this.viewTrailer.bind(this)}
value="Play Trailer"
/>
<input
className="btn btn-primary"
type="button"
onClick={this.viewMovie.bind(this)}
value="View"
/>
</td>
</tr>
</tbody>
</table>
);
}
}
export default MovieRow;
I see a lot of problems going on here. One is that row state is not initialized.
You should always initialize a state on the constructor
this.state = {
row: []
};
The other problem I saw is that you shouldn't be storing components in state.
See this
State should contain data that a component's event handlers may change to trigger a UI update. In real apps this data tends to be very small and JSON-serializable. When building a stateful component, think about the minimal possible representation of its state, and only store those properties in this.state. Inside of render() simply compute any other information you need based on this state. You'll find that thinking about and writing applications in this way tends to lead to the most correct application, since adding redundant or computed values to state means that you need to explicitly keep them in sync rather than rely on React computing them for you.
What you can do instead is rewriting your state like
this.state = {
movies: []
}
And inside your ajax request
// Change these lines to
results.forEach(movie => {
movie.video_src = movie.key;
console.log(movie.video_src);
var videoRow = <MovieRow key={movie.id} movie={movie} />;
videoRows.push(videoRow);
});
// To this
results.forEach(movie => {
movie.video_src = movie.key;
videoRows.push(movie);
});
this.setState({ movies: videoRows });
And lastly inside your render method, loop all the movies in your state and and return
your MovieRow component
{this.state.movies.map(movie => <MovieRow key={movie.id} movie={movie}/>)}

Datatable not refreshing on save

I want my table to refresh on save click, it's working for normal table with *ngFor, but I'm using Smartadmin angular template. I think the solution may be related to table.ajax.reload() , but how do i execute this in angular way.
save-tax.component.ts
import { Component, OnInit, Input ,Output, EventEmitter } from '#angular/core';
// Forms related packages
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { FormValidation } from 'app/shared/validators/formValidation'; //custom form validation
import { ConfigurationService } from 'app/+configuration/configuration.service';
import { FlashMessagesService } from 'angular2-flash-messages';
#Component({
selector: 'save-tax',
templateUrl: './save-tax.component.html'
})
export class SaveTaxComponent implements OnInit {
#Output() reloadTableData = new EventEmitter();
saveTaxForm: FormGroup;
constructor(private _fb: FormBuilder,
private _config: ConfigurationService,
private _flash: FlashMessagesService) { }
ngOnInit() {
this.saveTaxForm_builder();
}
saveTaxForm_builder() {
this.saveTaxForm = this._fb.group({
tax_title: [null, [
Validators.required
]],
tax_rate: [null, [
Validators.required,
Validators.pattern(FormValidation.patterns().price),
]],
});
}
tTitle = "input"; tRate = "input";
validInput(val) {
var classSuccess = "input state-success";
val == 'tax_title' ? this.tTitle = classSuccess : null;
val == 'tax_rate' ? this.tRate = classSuccess : null;
}
invalidInput(val) {
var classError = "input state-error";
val == 'tax_title' ? this.tTitle = classError : null;
val == 'tax_rate' ? this.tRate = classError : null;
}
classReset() {
this.tTitle = "input";
this.tRate = "input";
}
save_tax() {
if (this.saveTaxForm.value) {
this._config.createTax(this.saveTaxForm.value).subscribe(data => {
if (data.success) {
this._flash.show(data.msg, { cssClass: 'alert alert-block alert-success', timeout: 1000 });
this.saveTaxForm.reset();
this.classReset();
this.reloadTableData.emit(); // Emitting an event
} else {
this.saveTaxForm.reset();
this.classReset();
this._flash.show(data.msg, { cssClass: 'alert alert-block alert-danger', timeout: 3500 });
}
},
error => {
this.saveTaxForm.reset();
this.classReset();
this._flash.show("Please contact customer support. " + error.status + ": Internal server error.", { cssClass: 'alert alert-danger', timeout: 5000 });
});
} else {
this._flash.show('Something went wrong! Please try again..', { cssClass: 'alert alert-warning', timeout: 3000 });
}
}
}
datatable.component.ts
import {Component, Input, ElementRef, AfterContentInit, OnInit} from '#angular/core';
declare var $: any;
#Component({
selector: 'sa-datatable',
template: `
<table class="dataTable responsive {{tableClass}}" width="{{width}}">
<ng-content></ng-content>
</table>
`,
styles: [
require('smartadmin-plugins/datatables/datatables.min.css')
]
})
export class DatatableComponent implements OnInit {
#Input() public options:any;
#Input() public filter:any;
#Input() public detailsFormat:any;
#Input() public paginationLength: boolean;
#Input() public columnsHide: boolean;
#Input() public tableClass: string;
#Input() public width: string = '100%';
constructor(private el: ElementRef) {
}
ngOnInit() {
Promise.all([
System.import('script-loader!smartadmin-plugins/datatables/datatables.min.js'),
]).then(()=>{
this.render()
})
}
render() {
let element = $(this.el.nativeElement.children[0]);
let options = this.options || {}
let toolbar = '';
if (options.buttons)
toolbar += 'B';
if (this.paginationLength)
toolbar += 'l';
if (this.columnsHide)
toolbar += 'C';
if (typeof options.ajax === 'string') {
let url = options.ajax;
options.ajax = {
url: url,
complete: function (xhr) {
options.ajax.reload();
}
}
}
options = $.extend(options, {
"dom": "<'dt-toolbar'<'col-xs-12 col-sm-6'f><'col-sm-6 col-xs-12 hidden-xs text-right'" + toolbar + ">r>" +
"t" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>",
oLanguage: {
"sSearch": "<span class='input-group-addon'><i class='glyphicon glyphicon-search'></i></span> ",
"sLengthMenu": "_MENU_"
},
"autoWidth": false,
retrieve: true,
responsive: true,
initComplete: (settings, json)=> {
element.parent().find('.input-sm', ).removeClass("input-sm").addClass('input-md');
}
});
const _dataTable = element.DataTable(options);
if (this.filter) {
// Apply the filter
element.on('keyup change', 'thead th input[type=text]', function () {
_dataTable
.column($(this).parent().index() + ':visible')
.search(this.value)
.draw();
});
}
//custom functions
element.on('click', 'delete', function () {
var tr = $(this).closest('tr');
var row = _dataTable.row( tr );
if ( $(this).hasClass('delete') ) {
row.remove().draw(false);
console.log(row);
}
else {
//$(table).$('tr.selected').removeClass('selected');
$(this).addClass('selected');
}
console.log($(this).attr("class"))
});
//end custom functions
if (!toolbar) {
element.parent().find(".dt-toolbar").append('<div class="text-right"><img src="assets/img/logo.png" alt="SmartAdmin" style="width: 111px; margin-top: 3px; margin-right: 10px;"></div>');
}
if(this.detailsFormat){
let format = this.detailsFormat
element.on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = _dataTable.row( tr );
if ( row.child.isShown() ) {
row.child.hide();
tr.removeClass('shown');
}
else {
row.child( format(row.data()) ).show();
tr.addClass('shown');
}
})
}
}
}
tax-list.component.html
<!-- NEW COL START -->
<article class="col-sm-12 col-md-12 col-lg-12">
<!-- Widget ID (each widget will need unique ID)-->
<div sa-widget [editbutton]="false" [custombutton]="false">
<header>
<span class="widget-icon"> <i class="fa fa-percent"></i> </span>
<h2>Tax Rule List</h2>
</header>
<!-- widget div-->
<div>
<!-- widget content -->
<div class="widget-body no-padding">
<sa-datatable [options]="tableData" paginationLength="true" tableClass="table table-striped table-bordered table-hover" width="100%">
<thead>
<tr>
<th data-hide="phone"> ID </th>
<th data-hide="phone,tablet">Tax Title</th>
<th data-class="expand">Tax Rate</th>
<th data-hide="phone,tablet">Status</th>
<th data-hide="phone,tablet"> Action </th>
</tr>
</thead>
</sa-datatable>
</div>
<!-- end widget content -->
</div>
<!-- end widget div -->
</div>
<!-- end widget -->
</article>
<!-- END COL -->
tax-list.component.ts
import { FlashMessagesService } from 'angular2-flash-messages';
import { ConfigurationService } from 'app/+configuration/configuration.service';
import { Component, OnInit } from '#angular/core';
declare var $: any;
#Component({
selector: 'tax-list',
templateUrl: './tax-list.component.html'
})
export class TaxListComponent implements OnInit {
tableData: any;
constructor(private _config: ConfigurationService, private _flash: FlashMessagesService) { }
ngOnInit() {
this.fetchTableData();
this.buttonEvents();
}
fetchTableData() {
this.tableData = {
ajax: (data, callback, settings) => {
this._config.getTaxRules().subscribe(data => {
if (data.success) {
callback({
aaData: data.data
});
} else {
alert(data.msg);
}
},
error => {
alert('Internal server error..check database connection.');
});
},
serverSIde:true,
columns: [
{
render: function (data, type, row, meta) {
return meta.row + 1;
}
},
{ data: 'tax_title' },
{ data: 'tax_rate' },
{ data: 'status' },
{
render: function (data, type, row) {
return `<button type="button" class="btn btn-warning btn-xs edit" data-element-id="${row._id}">
<i class="fa fa-pencil-square-o"></i> Edit</button>
<button type="button" class="btn btn-danger btn-xs delete" data-element-id="${row._id}">
<i class="fa fa-pencil-square-o"></i> Delete</button>`;
}
}
],
buttons: [
'copy', 'pdf', 'print'
]
};
}
buttonEvents(){
document.querySelector('body').addEventListener('click', (event) => {
let target = <Element>event.target; // Cast EventTarget into an Element
if (target.tagName.toLowerCase() === 'button' && $(target).hasClass('edit')) {
this.tax_edit(target.getAttribute('data-element-id'));
}
if (target.tagName.toLowerCase() === 'button' && $(target).hasClass('delete')) {
this.tax_delete(target.getAttribute('data-element-id'));
}
});
}
tax_edit(tax_id) {
}
tax_delete(tax_id) {
this._config.deleteTaxById(tax_id).subscribe(data => {
if (data.success) {
this._flash.show(data.msg, { cssClass: 'alert alert-info fade in', timeout: 3000 });
this.fetchTableData();
} else {
this._flash.show(data.msg, { cssClass: 'alert alert-warning fade in', timeout: 3000 });
}
},
error => {
this._flash.show(error, { cssClass: 'alert alert-warning fade in', timeout: 3000 });
});
}
reloadTable(){
this.ngOnInit();
}
}
You can add a refresh button in your widget using <div class='widget-toolbar'>...</div> and using (click) event binding, attach a method with it. I named it as onRefresh() ...
<div sa-widget [editbutton]="false" [colorbutton]="false">
<header>
<span class="widget-icon">
<i class="fa fa-chart"></i>
</span>
<h2>Sample Datatable</h2>
<div class="widget-toolbar" role="menu">
<a class="glyphicon glyphicon-refresh" (click)="onRefresh('#studentTable table')"></a>
</div>
</header>
<div>
<div class="widget-body no-padding">
<sa-datatable id="studentTable" [options]="datatableOptions" tableClass="table table-striped table-bordered table-hover table-responsive">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Rank</th>
<th>Options</th>
</tr>
</thead>
</sa-datatable>
</div>
</div>
</div>
Focus at the method which I have given in the click event binding, I passed the id of the <sa-datatable> with table, that is #studentTable table that mentions the table tag according to the datatable implementation of the smartadmin.
Now in the component, add a method 'onRefresh()' which should be like
onRefresh(id: any) {
if ($.fn.DataTable.isDataTable(id)) {
const table = $(id).DataTable();
table.ajax.reload();
}
}
In this method, that #studentTable table will come in this id which is a parameter in the method. Using jQuery you can do the table.ajax.reload().
But you need to declare the jQuery at the top.
declare var $ : any;
app.component.ts
import { Component, OnInit, OnDestroy } from '#angular/core';
declare var $: any;
#Component({
selector: 'app-order',
templateUrl: './order.component.html',
styleUrls: ['./order.component.css']
})
export class OrderComponent implements OnInit, OnDestroy {
datatableOptions:{
...
}
constructor(){
...
}
ngOnInit(){
...
}
onRefresh(){
if ($.fn.DataTable.isDataTable(id)) {
const table = $(id).DataTable();
table.ajax.reload();
}
}
}

Thinkster Mean stack tutorial displaying blank page

I am trying to do this tutorial and at first it was all fine but after using the angular ui-router when i run the server all I get is a blank page. I can insert into db via terminal and the jason data are all working fine but the page is loading to a blank page...
public/javascripts/angularApp
var app = angular.module('flapperNews', [require('angular-ui-router')]);
app.factory('posts', ['$http',function($http){
var o = {
posts: []
};
return o;
o.getAll = function() {
return $http.get('/posts').success(function(data){
angular.copy(data, o.posts);
});
};
}]);
app.controller('MainCtrl', [
'$scope',
'posts',
function($scope, posts){
$scope.posts = posts.posts[$stateParams.id];
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
$scope.posts.push({title: $scope.title, link: $scope.link, upvotes: 0});
$scope.title = '';
$scope.link = '';
};
$scope.incrementUpvotes = function(post) {
post.upvotes += 1;
};
}]);
app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/home.html',
controller: 'MainCtrl'
resolve: {
postPromise: ['posts', function(posts){
return posts.getAll();
}]
}
});
.state('posts', {
url: '/posts/{id}',
templateUrl: '/posts.html',
controller: 'PostsCtrl'
});
$urlRouterProvider.otherwise('home');
}]);
app.controller('PostsCtrl', [
'$scope',
'$stateParams',
'posts',
function($scope, $stateParams, posts){
$scope.addComment = function(){
if($scope.body === '') { return; }
$scope.post.comments.push({
body: $scope.body,
author: 'user',
upvotes: 0
});
$scope.body = '';
};
}]);
routes/index.js`
var mongoose = require('mongoose');
var express = require('express');
var router = express.Router();
var Post = mongoose.model('Post');
var Comment = mongoose.model('Comment')
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/posts', function(req, res, next) {
Post.find(function(err, posts){
if(err){ return next(err); }
res.json(posts);
});
});
/* for saving post into db */
router.post('/posts', function(req, res, next) {
var post = new Post(req.body);
post.save(function(err, post){
if(err){ return next(err); }
res.json(post);
});
});
/* for retriving one post from db */
router.param('post', function(req, res, next, id) {
var query = Post.findById(id);
query.exec(function (err, post){
if (err) { return next(err); }
if (!post) { return next(new Error('can\'t find post')); }
req.post = post;
return next();
});
});
/* for retriving one comment from db */
router.param('comment', function(req, res, next, id) {
var query = Post.findById(id);
query.exec(function (err, comment){
if (err) { return next(err); }
if (!comment) { return next(new Error('can\'t find comment')); }
req.comment = comment;
return next();
});
});
/*for displaying the retrieved post*/
router.get('/posts/:post', function(req, res) {
res.json(req.post);
});
/*for displaying the post upvote*/
router.put('/posts/:post/upvote', function(req,res,next){
req.post.populate('comment',function(err,post){
if(err){return next(err);}
res.json(post);
});
});
/*saving comment*/
router.post('/posts/:post/comments',function(req, res, next){
var comment = new Comment(req.body);
comment.post = req.post;
comment.save(function(err,comment){
if(err){return next(err);}
req.post.comments.push(comment);
req.post.save(function(err,post){
if(err){return next(err);}
res.json(comment);
});
});
});
/*display comment upvote*/
router.put('/posts/:post/comments/:comment/upvote', function(req,res,next){
req.comment.upvote(function(err,comment){
if(err){return next(err);}
res.json(comment);
});
});
module.exports = router;
views/index.ejs
<html>
<head>
<title>My Angular App!</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
<script src="/javascripts/angularApp.js"></script>
<style> .glyphicon-thumbs-up { cursor:pointer } </style>
</head>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<ui-view></ui-view>
</div>
</div>
<script type="text/ng-template" id="/home.html">
<div class="page-header">
<h1>Flapper News</h1>
</div>
<div ng-repeat="post in posts | orderBy: '-upvotes'">
<span class="glyphicon glyphicon-thumbs-up" ng-click="upvote(post)"> </span>
{{post.upvotes}}
<span class="glyphicon glyphicon-thumbs-down" ng-click="downvote(post)"></span>
<span style="font-size:20px;margin-left:10px">
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
<span ng-show="post.author">
posted by <a>{{post.author}}</a> |
</span>
</span>
<span>
Comments
({{post.comments.length}})
</span>
</div>
<form ng-submit="addPost()" ng-show="isLoggedIn()" style="margin-top:30px">
<h3>Add a new post:</h3>
<div class="form-group">
<input type="text" class="form-control" placeholder="Title" ng-model="title">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="Link" ng-model="link">
</div>
<button type="submit" class="btn btn-primary">Post</button>
</form>
<div ng-hide="isLoggedIn()">
<h3>You need to Log In or Register before you can add a post.</h3>
</div>
</script>
<script type="text/ng-template" id="/posts.html">
<div class="page-header">
<h3>
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
</h3>
</div>
<div ng-repeat="comment in post.comments | orderBy:'-upvotes'">
<span class="glyphicon glyphicon-thumbs-up" ng-click="upvote(comment)"></span>
{{comment.upvotes}}
<span class="glyphicon glyphicon-thumbs-down" ng-click="downvote(comment)"></span>
- by {{comment.author}}
<span style="font-size:20px; margin-left:10px;">
{{comment.body}}
</span>
</div>
<form ng-submit="addComment()"
style="margin-top:30px;">
<h3>Add a new comment</h3>
<div class="form-group">
<input type="text"
class="form-control"
placeholder="Comment"
ng-model="body"></input>
</div>
<button type="submit" class="btn btn-primary">Post</button>
</form>
</script>
</body>
app.js
var mongoose = require('mongoose');
require('./models/Posts');
require('./models/Comments');
mongoose.connect('mongodb://localhost/news');
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
I had the same problem as well. They need to fix it in the tutorial, but in in your angularApp.js file you have this:
var app = angular.module('flapperNews', [require('angular-ui-router')]);
For ui-router, you actually have to inject it like so:
var app = angular.module('flapperNews', ['ui.router']);
Hope that helps!
Personally, I also just created separate files for my views so that I could add to it later a little neater since I don't like having all that on my index page.
In your Angularapp file, try moving your return o statement below the o.getAll() function so you actually get the posts loaded in the array before it is returned. This worked for me.
app.factory('posts', ['$http', function($http){
var o = {
posts: []
};
o.getAll = function() {
return $http.get('/posts').success(function(data){
angular.copy(data, o.posts);
});
};
return o;
}]);

Resources