#call method in parent component vue
Explore tagged Tumblr posts
codehunger · 4 years ago
Text
VueJs - How to call a method from non-parent-child component in vue-js
VueJs – How to call a method from non-parent-child component in vue-js
If you have an idea about the vue js then you know that how we can pass variables or methods in vue js , basically we use the props to do such activity, but what if there is no parent-child relation in the component, and you can want to call those methods. You can also read: How to pass value to child component in Vue.js Let’s suppose I have two components, one name is ComponentOne.vue and…
Tumblr media
View On WordPress
1 note · View note
forcetalks001 · 3 years ago
Text
An Introduction to Lightning Web Components | Salesforce Lightning
Lightning web components are custom HTML components fabricated using HTML and standard JavaScript. Lightning web components and Aura components can coexist and interoperate on a page.  For both administrators & users, it shows up as components. In this top blog on salesforce, we will talk in detail about the Lighting web components and discuss in detail how it works.
Lightning Web Components is built on top of standard Web Components technologies and provides only what is necessary to perform well in browsers supported by Salesforce. Because it runs natively in browsers, Lightning Web Components is lightweight and delivers exceptional performance. Much of the code you write is standard JavaScript and HTML.
It is open source, that engages you to examine the source code, modify the behavior for your requirements, and gather enterprise-ready web components on any platform, not just Salesforce. 
Previously, we required different frameworks to manufacture different sides of an application that encouraged external Salesforce. For example, we used the Aura component to develop the employee-defying side of an application on Salesforce. And also we used React, Angular, or Vue to build the customer-defying side of the application, and passed it on to Heroku or on another platform. Today, we can use Lightning web components to fabricate both sides of the application. The advantages of it are huge and with assistance from Top Salesforce Consultants, you would now be able to learn the framework at ease.
We can simply create lightning web components using HTML, javascript, and CSS. 
Benefits of Lightning Web Components
It gives an easy way to develop large-scale modular apps 
Also, we got the leverage of the latest web functionalities and constructs 
A web developer who is working on modern JS frameworks could easily ramp-up LWC 
Interoperable components 
Allow better performance
With the right assistance from Salesforce Consulting Companies, you can take the leverage of lightning web components at ease
These are the Fundamentals Pieces of your Component
HTML gives the structure to your component.
JavaScript describes the centre's business logic and handles events.
CSS gives the look, feel, and animation to your component.
Don't forget to check out: How to Convert sforce.apex.execute to Lightning | Salesforce Developer Guide
Let’s take a simple example of the Lightning web component:
HTML:
<template>
<input value={message}></input>
</template>
JavaScript:
import { LightningElement } from 'lwc';
export default class App extends LightningElement {
message = 'Hello World';
}
CSS:
input {
color: red;
}
Decorators in Lightning Web Component
LWC has three decorators that append functionality to property or function. The capability to create decorators is part of ECMAScript and these three decorators are unique to LWC.
@api: It is used to expose public property. And the public property is reactive & if you want to change the reactive property value, the component is re-rendered. So you know that when a component is rerendered, all the expressions used in the template are reconsidered once again. @api passes the public property values from the parent component. If you want to use @api decorators, you have to import it explicitly from lwc. Import { LightningElement, api } from ‘lwc’;
@track: If you want to track private reactive property value  & also rerender a component when it changes, decorate it with @track. We can use the private property only in the component where it is defined. If you want to use @api decorators, you have to import it explicitly from lwc. Import { LightningElement, track } from ‘lwc’; 
@wire: It is used to read the Salesforce data. LWC uses a reactive wire service. @wire is used to call apex method in lwc js controller. If you want to use @api decorators, you have to import it explicitly from lwc. Import { LightningElement, wire } from ‘lwc’;
Check out another amazing blog by Shweta here: Stages of Salesforce CPQ Implementation
And also you have to import wire Syntax as shown below:
Import apexMethodName from '@salesforce/apex/Namespace.Classname.apexMethodReference';
apexMethodName: It recognizes the apex method.
apexMethodReference: Imported Apex method name.
Classname: Apex class name.
Namespace: You know that the default namespace of the Salesforce org is ‘c’, in this case, don’t specify a namespace. The namespace is used when your apex class is in a managed package.
Important point: For property, we can have only one decorator at a time.
0 notes
holytheoristtastemaker · 5 years ago
Link
 Have you ever seen a calendar on a webpage and thought, how the heck did they did that? For something like that, it might be natural to reach for a plugin, or even an embedded Google Calendar, but it’s actually a lot more straightforward to make one than you might think. Especially when we use the component-driven power of Vue.
I’ve set up a demo over at CodeSandbox so you can see what we’re aiming for, but it’s always a good idea to spell out what we’re trying to do:
Create a month view grid that displays the days of the current month
Display dates from the previous and next months to so the grid is always full
Indicate the current date
Show the name of the currently selected month
Navigate to the previous and next month
Allow the user to navigate back to the current month with a single click
Oh, and we’ll build this as a single page application that fetches calendar dates from Day.js, a super light utility library.
Step 1: Start with the basic markup
We’re going to jump straight into templates. If you’re new to Vue, Sarah’s introduction series is a nice place to start. It’s also worth noting that I’ll be linking to the Vue 2 docs throughout this post. Vue 3 is currently in beta and the docs for it are subject to change.
Let’s start with creating a basic template for our calendar. We can outline our markup as three layers where we have:
A section for the calendar header. This will show components with the currently selected month and the elements responsible for paginating between months.
A section for the calendar grid header. A table header that holds a list containing the days of the week, starting with Monday.
The calendar grid. You know, each day in the current month, represented as a square in the grid.
Let’s write this up in a file called CalendarMonth.vue. This will be our main component.
<!-- CalendarMonth.vue --> <template>   <!-- Parent container for the calendar month -->   <div class="calendar-month">          <!-- The calendar header -->     <div class="calendar-month-header"       <!-- Month name -->       <CalendarDateIndicator />       <!-- Pagination -->       <CalendarDateSelector />     </div>     <!-- Calendar grid header -->     <CalendarWeekdays />     <!-- Calendar grid -->     <ol class="days-grid">       <CalendarMonthDayItem />     </ol>   </div> </template>
Now that we have some markup to work with, let’s go one step further and create required components.
Step 2: Header components
In our header we have two components:
CalendarDateIndicator shows the currently selected month.
CalendarDateSelector is responsible for paginating between months.
Let’s start with CalendarDateIndicator. This component will accept a selectedDate property which is a Day.js object that will format the current date properly and show it to the user.
<!-- CalendarDateIndicator.vue --> <template>   <div class="calendar-date-indicator"></div> </template> <script> export default {   props: {   selectedDate: {     type: Object,     required: true   } },   computed: {     selectedMonth() {       return this.selectedDate.format("MMMM YYYY");     }   } }; </script>
That was easy. Let’s go and create the pagination component that lets us navigate between months. It will contain three elements responsible for selecting the previous, current and next month. We’ll add an event listener on those that fires the appropriate method when the element is clicked.
<!-- CalendarDateSelector.vue --> <template>   <div class="calendar-date-selector">     <span @click="selectPrevious">﹤</span>     <span @click="selectCurrent">Today</span>     <span @click="selectNext">﹥</span>   </div> </template>
Then, in the script section, we will set up two props that the component will accept:
currentDate allows us to come back to current month when the “Today” button is clicked.
selectedDate tells us what month is currently selected.
We will also define methods responsible for calculating the new selected date based on the currently selected date using the subtract and add methods from Day.js. Each method will also $emit an event to the parent component with the newly selected month. This allows us to keep the value of selected date in one place — which will be our CalendarMonth.vue component — and pass it down to all child components (i.e. header, calendar grid).
// CalendarDateSelector.vue <script> import dayjs from "dayjs"; export default {   name: "CalendarDateSelector",   props: {     currentDate: {       type: String,       required: true     },     selectedDate: {       type: Object,       required: true     }   },   methods: {     selectPrevious() {       let newSelectedDate = dayjs(this.selectedDate).subtract(1, "month");       this.$emit("dateSelected", newSelectedDate);     },     selectCurrent() {       let newSelectedDate = dayjs(this.currentDate);       this.$emit("dateSelected", newSelectedDate);     },     selectNext() {       let newSelectedDate = dayjs(this.selectedDate).add(1, "month");       this.$emit("dateSelected", newSelectedDate);     }   } }; </script>
Now, let’s go back to the CalendarMonth.vue component and use our newly created components.
To use them we first need to import and register the components, also we need to create the values that will be passed as props to those components:
today properly formats today’s date and is used as a value for the “Today” pagination button.
selectedDate is the currently selected date (set to today’s date by default).
The last thing we need to do before we can render the components is create a method that’s responsible for changing the value of selectedDate. This method will be fired when the event from the pagination component is received.
// CalendarMonth.vue <script> import dayjs from "dayjs"; import CalendarDateIndicator from "./CalendarDateIndicator"; import CalendarDateSelector from "./CalendarDateSelector"; export default {   components: {     CalendarDateIndicator,     CalendarDateSelector   },   data() {     return {       selectedDate: dayjs(),       today: dayjs().format("YYYY-MM-DD")     };   },   methods: {     selectDate(newSelectedDate) {       this.selectedDate = newSelectedDate;     }   } }; </script>
Now we have everything we need to render our calendar header:
<!-- CalendarMonth.vue --> <template>   <div class="calendar-month">     <div class="calendar-month-header">       <CalendarDateIndicator         :selected-date="selectedDate"         class="calendar-month-header-selected-month"       />       <CalendarDateSelector         :current-date="today"         :selected-date="selectedDate"         @dateSelected="selectDate"       />     </div>   </div> </template>
This is a good spot to stop and see what we have so far. Our calendar header is doing everything we want, so let’s move forward and create components for our calendar grid.
Step 3: Calendar grid components
Here, again, we have two components:
CalendarWeekdays shows the names of the weekdays.
CalendarMonthDayItem represents a single day in the calendar.
The CalendarWeekdays component contains a list that iterates through the weekday labels (using the v-for directive) and renders that label for each weekday. In the script section, we need to define our weekdays and create a computed property to make it available in the template and cache the result to prevent us from having to re-calculate it in the future.
// CalendarWeekdays.vue <template>   <ol class="day-of-week">     <li v-for="weekday in weekdays" :key="weekday" > </li>   </ol> </template> 
 <script> const WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; export default {   name: 'CalendarWeekdays',   computed: {     weekdays() {       return WEEKDAYS     }   } } </script>
Next is CalendarMonthDayItem. It’s a list item that receives a day property that is an object, and a boolean prop, isToday, that allows us to style the list item to indicate that it’s the current date. We also have one computed property that formats the received day object to our desired date format (D, or the numeric day of the month).
// CalendarMonthDayItem.vue <template>   <li     class="calendar-day"     :class="{       'calendar-day--not-current': !isCurrentMonth,       'calendar-day--today': isToday     }"   >     <span></span>   </li> </template> 
 <script> import dayjs from "dayjs"; export default {   name: "CalendarMonthDayItem",   props: {     day: {       type: Object,       required: true     },     isCurrentMonth: {       type: Boolean,       default: false     },     isToday: {       type: Boolean,       default: false     }   },   computed: {     label() {       return dayjs(this.day.date).format("D");     }   } }; </script>
OK, now that we have these two components, let’s see how we can add them to our CalendarMonth component.
We first need to import and register them. We also need to create a computedproperty that will return an array of objects representing our days. Each day contains a date property and isCurrentMonth property.
// CalendarMonth.vue <script> import dayjs from "dayjs"; import CalendarMonthDayItem from "./CalendarMonthDayItem"; import CalendarWeekdays from "./CalendarWeekdays"; 
 export default {   name: "CalendarMonth",   components: {     // ...     CalendarMonthDayItem,     CalendarWeekdays   },   computed: {     days() {       return [         { date: "2020-06-29", isCurrentMonth: false },         { date: "2020-06-30", isCurrentMonth: false },         { date: "2020-07-01", isCurrentMonth: true },         { date: "2020-07-02", isCurrentMonth: true },         // ...         { date: "2020-07-31", isCurrentMonth: true },         { date: "2020-08-01", isCurrentMonth: false },         { date: "2020-08-02", isCurrentMonth: false }       ];     }   } }; </script>
Then, in the template, we can render our components. Again, we use the v-fordirective to render the required number of day elements.
<!-- CalendarMonth.vue --> <template>   <div class="calendar-month">     <div class="calendar-month-header">       // ...     </div>     <CalendarWeekdays/>     <ol class="days-grid">       <CalendarMonthDayItem         v-for="day in days"         :key="day.date"         :day="day"         :is-today="day.date === today"       />     </ol>   </div> </template>
OK, things are starting to look good now. Have a look at where we are. It looks nice but, as you probably noticed, the template only contains static data at the moment. The month is hardcoded as July and the day numbers are hardcoded as well. We will change that by calculating what date should be shown on a specific month. Let’s dive into the code!
Step 4: Setting up current month calendar
Let’s think how we can calculate the date that should be shown on a specific month. That’s where Day.js really comes into play. It provides all the data we need to properly place dates on the correct days of the week for a given month using real calendar data. It allows us to get and set anything from the start date of a month to all the date formatting options we need to display the data.
We will:
Get the current month
Calculate where the days should be placed (weekdays)
Calculate the days for displaying dates from the previous and next months
Put all of the days together in a single array
We already have Day.js imported in our CalendarMonth component. We’re also going to lean on a couple of Day.js plugins for help. WeekDay helps us set the first day of the week. Some prefer Sunday as the first day of the week. Other prefer Monday. Heck, in some cases, it makes sense to start with Friday. We’re going to start with Monday.
The WeekOfYear plugin returns the numeric value for the current week out of all weeks in the year. There are 52 weeks in a year, so we’d say that the week starting January 1 is the the first week of the year, and so on.
Here’s what we put into CalendarMonth.vue to put all of that to use:
// CalendarMonth.vue <script> import dayjs from "dayjs"; import weekday from "dayjs/plugin/weekday"; import weekOfYear from "dayjs/plugin/weekOfYear"; // ... 
 dayjs.extend(weekday); dayjs.extend(weekOfYear); // ...
That was pretty straightforward but now the real fun starts as we will now play with the calendar grid. Let’s stop for a second a think what we really need to do to get that right.
First, we want the date numbers to fall in the correct weekday columns. For example, July 1, 2020, is on a Wednesday. That’s where the date numbering should start.
If the first of the month falls on Wednesday, then that means we’ll have empty grid items for Monday and Tuesday in the first week. The last day of the month is July 31, which falls on a Friday. That means Saturday and Sunday will be empty in the last week of the grid. We want to fill those with the trailing and leading dates of the previous and next months, respectively, so that the calendar grid is always full.
Tumblr media
Adding dates for the current month
To add the days of the current month to the grid, we need to know how many days exist in the current month. We can get that using the daysInMonth method provided by Day.js. Let’s create a computed property for that.
// CalendarMonth.vue computed: {   // ...   numberOfDaysInMonth() {       return dayjs(this.selectedDate).daysInMonth();   } }
When we know that, we create an empty array with a length that’s equal to number of days in the current month. Then we map() that array and create a day object for each one. The object we create has an arbitrary structure, so you can add other properties if you need them.
In this example, though, we need a date property that will be used to check if a particular date is the current day. We’ll also return a isCurrentMonth value that checks whether the date is in the current month or outside of it. If it is outside the current month, we will style those so folks know they are outside the range of the current month.
// CalendarMonth.vue computed: {   // ...   currentMonthDays() {     return [...Array(this.numberOfDaysInMonth)].map((day, index) => {       return {         date: dayjs(`${this.year}-${this.month}-${index + 1}`).format("YYYY-MM-DD")         isCurrentMonth: true       };     });   }, }
Adding dates from the previous month
To get dates from the previous month to display in the current month, we need to check what the weekday of the first day is in selected month. That’s where we can use the WeekDay plugin for Day.js. Let’s create a helper method for that.
// CalendarMonth.vue methods: {   // ...   getWeekday(date) {     return dayjs(date).weekday();   }, }
Then, based on that, we need to check which day was the last Monday in the previous month. We need that value to know how many days from the previous month should be visible in the current month view. We can get that by subtracting the weekday value from the first day of the current month. For example, if first day of the month is Wednesday, we need to subtract three days to get last Monday of the previous month. Having that value allows us to create an array of day objects starting from the last Monday of the previous month through the end of that month.
// CalendarMonth.vue computed: {   // ...   previousMonthDays() {     const firstDayOfTheMonthWeekday = this.getWeekday(this.currentMonthDays[0].date);     const previousMonth = dayjs(`${this.year}-${this.month}-01`).subtract(1, "month");     const previousMonthLastMondayDayOfMonth = dayjs(this.currentMonthDays[0].date).subtract(firstDayOfTheMonthWeekday - 1, "day").date();     // Cover first day of the month being sunday      (firstDayOfTheMonthWeekday === 0)     const visibleNumberOfDaysFromPreviousMonth = firstDayOfTheMonthWeekday ? firstDayOfTheMonthWeekday - 1 : 6;     return [...Array(visibleNumberOfDaysFromPreviousMonth)].map((day, index) = {       return {         date: dayjs(`${previousMonth.year()}-${previousMonth.month() + 1}-${previousMonthLastMondayDayOfMonth + index}`).format("YYYY-MM-DD"),         isCurrentMonth: false       };     });   } }
Adding dates from the next month
Now, let’s do the reverse and calculate which days we need from the next month to fill in the grid for the current month. Fortunately, we can use the same helper we just created for the previous month calculation. The difference is that we will calculate how many days from the next month should be visible by subtracting that weekday numeric value from seven.
So, for example, if the last day of the month is Saturday, we need to subtract one day from seven to construct an array of dates needed from next month (Sunday).
// CalendarMonth.vue computed: {   // ...   nextMonthDays() {     const lastDayOfTheMonthWeekday = this.getWeekday(`${this.year}-${this.month}-${this.currentMonthDays.length}`);     const nextMonth = dayjs(`${this.year}-${this.month}-01`).add(1, "month");     const visibleNumberOfDaysFromNextMonth = lastDayOfTheMonthWeekday ? 7 - lastDayOfTheMonthWeekday : lastDayOfTheMonthWeekday;     return [...Array(visibleNumberOfDaysFromNextMonth)].map((day, index) => {       return {         date: dayjs(`${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}`).format("YYYY-MM-DD"),         isCurrentMonth: false       };     });   } }
OK, we know how to create all days we need, so let’s use them and merge all days into a single array of all the days we want to show in the current month, including filler dates from the previous and next months.
// CalendarMonth.vue computed: {   // ...   days() {     return [       ...this.previousMonthDays,       ...this.currentMonthDays,       ...this.nextMonthDays     ];   }, }
0 notes
nancydsmithus · 6 years ago
Text
Building Mobile Apps With Ionic And React
Building Mobile Apps With Ionic And React
Ahmed Bouchefra
2019-08-07T12:30:00+02:002019-08-07T10:36:12+00:00
Ionic has recently added support for React; so now, React developers can get the advantages of Ionic to build hybrid mobile apps and progressive web apps (PWAs). In this post, we’ll show you how to get started using Ionic with React by building a simple demo app from scratch.
Prerequisites
In order to properly follow this tutorial, you’ll need the following prerequisites:
recent versions of Node.js and npm installed on your system,
working knowledge of TypeScript and React.
You can check that you have the latest Node.js version (v10) installed by running the following command:
$ node -v
Introducing React And Ionic
Let’s start with brief introductions to both React and Ionic.
According to the official website:
“React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It lets you compose complex UIs from small and isolated pieces of code called ‘components’.”
React focuses on building UIs and doesn’t provide any built-in tools for the common tasks required in web development, such as fetching remote data and routing, so you’ll need to use some existing third-party libraries for these tasks.
According to the Ionic website:
“Ionic Framework is the free, open-source mobile UI toolkit for developing high-quality cross-platform apps for native iOS, Android, and the web — all from a single codebase.”
Basically, it’s a set of UI components that you can use with plain JavaScript or any popular front-end framework or library, such as Angular, React or Vue, to build a hybrid mobile app and PWA.
In this tutorial, we’ll see and use some Ionic UI components such as the following:
IonMenu: With this, a navigation drawer will slide in from the side of the current view.
IonToolbar: These top bars are positioned above or below the content.
IonHeader: This parent component holds the toolbar component.
IonContent: This component provides a content area, with methods to control the scrollable area and other things. You need only one content component inside a single view.
IonList: This component contains items with similar data content, such as images and text. It’s made up of IonItem objects.
IonItem: This component may contain text, icons, avatars, images, inputs and any other native or custom element.
IonButton: This component provides a clickable element, which can be used in a form or anywhere that needs simple, standard button functionality.
Installing Ionic CLI v5
Ionic’s command line interface (CLI), version 5, has support for creating Ionic projects based on React. So, let’s get started by installing the tool from npm.
Open a CLI, and run the following command:
$ npm install -g ionic
At the time of writing, Ionic’s CLI v5.2.3 is the latest.
Note: *According to how you installed Node.js in your system, you may need to add sudo before your command in macOS or Linux or run the command prompt as administrator in Windows if you get any permission errors. You can also simply fix your npm permissions or use a tool such as nvm.*
Next, install Cordova Resources (which is used to generate Cordova resources locally) and Native Run (used to deploy app binaries to devices):
$ npm install -g cordova-res native-run
These are required only if you want to test your application on a real mobile device or emulator.
Creating An Ionic And React Project
Now, let’s create a project based on React. Go back to your terminal, make sure you are in your working directory, and run the following command:
$ ionic start myApp --type=react
We use --type=react to generate a project based on React. You’ll next need to choose a starter template from the available ones. Let’s pick sidemenu for a starter template with a side menu and navigation.
After generating the project and installing the dependencies, you can serve your app locally using the following commands:
$ cd ./myApp $ ionic serve
Your app will be available from the http://localhost:8100 address, and you can actually use your web browser to start playing with it.
Ionic is called a hybrid mobile framework because it makes use of web technologies that were originally designed to create web apps, along with a native container (Cordova or Capacitor), to build mobile apps without using native technologies for the target platforms, such as Java or Kotlin for Android or Swift for iOS.
Because your mobile app is actually a web application, you can do most development by testing in a web browser without using an emulator or a real mobile device, except for testing native device features such as the camera or the SQLite storage, in case you’ve used them in your app. In fact, it’s even possible to use certain techniques to mimic the plugins that provide the native features and do the entire testing during development in your web browser.
Cleaning Our Project
We have the app’s basic structure, with two pages (home and list) and a menu. Let’s remove the list page since it’s just boilerplate code.
First, remove the src/pages/List.tsx file, then open the src/App.tsx file, and remove the entry for the list page from the appPages array:
const appPages: AppPage[] = [ { title: 'Home', url: '/home', icon: home } ];
Also, remove the import of the list page from the file:
import List from './pages/List';
Next, remove <Route path="/:tab(home)/list" component={List} exact={true} /> from the App component:
const App: React.FunctionComponent = () => ( <IonApp> <IonReactRouter> <IonSplitPane contentId="main"> <Menu appPages={appPages} /> <IonPage id="main"> <IonRouterOutlet> <Route path="/:tab(home)" component={Home} exact={true} /> <Route exact path="/" render={() => <Redirect to="/home" />} /> </IonRouterOutlet> </IonPage> </IonSplitPane> </IonReactRouter> </IonApp> ); export default App;
The App component is the root component that gets rendered by our application. If you open the src/index.tsx file, you’ll find the following code:
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));
The render() method is used to render a React element into the DOM in the supplied root element.
Theming The App
Having created, served and cleaned our Ionic project, let’s now see how we can change the colors of the UI so that it looks more professional.
Let’s get started with the side menu. Open the src/components/Menu.tsx file, and add a color attribute with a primary value to the IonToolbar, IonContent, IonList and IonItem UI components:
const Menu: React.FunctionComponent = ({ appPages }) => ( <IonMenu contentId="main"> <IonHeader> <IonToolbar color="primary"> <IonTitle>Menu</IonTitle> </IonToolbar> </IonHeader> <IonContent color="primary"> <IonList style= color="primary"> {appPages.map((appPage, index) => { return ( <IonMenuToggle key={index} auto-hide="false"> <IonItem color="primary" href={appPage.url}> <IonIcon slot="start" icon={appPage.icon} /> <IonLabel>{appPage.title}</IonLabel> </IonItem> </IonMenuToggle> ); })} </IonList> </IonContent> </IonMenu> );
Ionic provides some default colors (primary, secondary, tertiary, success, warning, danger, light, medium and dark) that can be used to change the color of UI components. A color can be applied to an Ionic component in order to change the default colors using the color attribute. See “Colors” for more information.
These colors have default values, but you can customize them via some predefined CSS variables. See “Modifying Colors“.
This is a screenshot of our menu:
Tumblr media
Ionic menu. (Large preview)
Next, let’s change the color of the Home page. Open the src/pages/Home.tsx file, and set the color attribute of the IonToolbar and IonContent components to primary:
const HomePage: React.FunctionComponent = () => { return ( <> <IonHeader> <IonToolbar color="primary"> <IonButtons slot="start"> <IonMenuButton /> </IonButtons> <IonTitle>Home</IonTitle> </IonToolbar> </IonHeader> <IonContent color="primary" > </IonContent> </> ); };
This is a screenshot of the page:
Tumblr media
Ionic home. (Large preview)
Installing Axios And Consuming A REST API
We’ll see how to install Axios and consume a third-party RESTful API in our application, and we’ll also see how to display the fetched data using Ionic card and list components.
Having themed our application, let’s now see how to fetch data using Axios. We’ll use the third-party API available from NewsAPI.org.
First, we need to grab an API key, so that we can communicate with the API. Go to the registration page, enter your information, and register an account. You’ll be given an API key; note it, and let’s continue.
Head back to your terminal, and run the following command to install Axios:
$ npm install axios --save
Next, open the src/pages/Home.tsx file, and start by importing Axios and IonButton:
import { IonButton } from '@ionic/react'; import axios from 'axios';
Next, define the API_KEY and URL constant variables:
const API_KEY = "<YOUR_API_KEY_HERE>"; const URL = `https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=${API_KEY}`;
In the URL variable, we’ll add an endpoint to get the top headlines from our source, TechCrunch. You can use any source you want from the available sources.
Note: Make sure to put your own API key in the API_KEY variable.
Next, define the fetchArticles() method as follows:
const fetchArticles = () => { return axios({ url: URL, method: 'get' }).then(response => { console.log(response); return response.data; }) };
We simply call the axios() method to send a GET request to the news endpoint, and the result from the method is a promise that needs to be resolved in order to get the news data.
Next, update the HomePage component as follows to call the fetchArticles() method and resolve the returned promise:
const HomePage: React.FunctionComponent = () => { const [articles, setArticles] = React.useState([]); const items: any[] = []; React.useEffect(() => { fetchArticles().then(data => setArticles(data.articles)); }, []); return ( <> <IonHeader> <IonToolbar color="primary"> <IonButtons slot="start"> <IonMenuButton /> </IonButtons> <IonTitle>Home</IonTitle> </IonToolbar> </IonHeader> <IonContent color="primary" > <IonList color="primary"> { articles.map(a => { return ( <IonItem> {a['title']} <IonButton href={a['url']} color="primary" slot="end">Read</IonButton> </IonItem> ); }) } </IonList> </IonContent> </> ); };
In our function component, we first call the useState() hook of React to create the articles state variable, which will hold the news articles after we fetch them from the API.
useState() returns the state variable, which has the empty array as its initial value and a function that we can use to change the value of the variable. We use destructuring assignment to unpack the values from the returned pair into distinct variables (i.e. articles and setArticles()).
Next, we call the useEffect() hook to perform a side effect in our component. In our case, the side effect is to fetch data from the news API using the fetchArticles() method, which returns a promise. Once the promise is resolved, we call the setArticles() method to assign the news data to the articles variable.
Both useState() and useEffect() are built-in React hooks that were introduced in React 16.8; they simply let you use state and other React features without having to write a class. The useEffect() hook is equivalent to calling the componentDidMount, componentDidUpdate and componentWillUnmount lifecycle methods combined in class-based components.
Finally, in the view template, we iterate over the articles array using the map() method, and we display the title of each news article inside an IonItem element of the IonList component, and also a button that takes us to the page of the full article.
This is a screenshot of the page:
Tumblr media
Ionic news app (Large preview)
You can find the source code in this GitHub repository.
Conclusion
In this tutorial, we have started using both Ionic and React and used them to build a simple mobile application that fetches and displays news data from a third-party API using the Axios client. We have also seen how to use hooks in React — namely, the useState() and useEffect() hooks — to create state and perform side effects inside React function components. With Ionic, we’ve seen how easy it is to generate a project based on React and how we can theme the application using the color attributes of components.
Tumblr media
(dm, al, yk, ra, il)
0 notes
t-baba · 6 years ago
Photo
Tumblr media
A Beginner’s Guide to Working With Components in Vue
One of the great things about working with Vue is its component-based approach to building user interfaces. This allows you to break your application into smaller, reusable pieces (components) which you can then use to build out a more complicated structure.
In this guide, I’ll offer you a high-level introduction to working with components in Vue. I’ll look at how to create components, how to pass data between components (via both props and an event bus) and how to use Vue’s <slot> element to render additional content within a component.
Each example will be accompanied by a runnable CodePen demo.
How to Create Components in Vue
Components are essentially reusable Vue instances with a name. There are various ways to create components within a Vue application. For example, in a small- to medium-sized project you can use the Vue.component method to register a global component, like so:
Vue.component('my-counter', { data() { return { count: 0 } }, template: `<div></div>` }) new Vue({ el: '#app' })
The name of the component is my-counter. It can be used like so:
<div id="app"> <my-counter></my-counter> </div>
When naming your component, you can choose kebab case (my-custom-component) or Pascal case (MyCustomComponent). You can use either variation when referencing your component from within a template, but when referencing it directly in the DOM (as in the example above), only the kebab case tag name is valid.
You might also notice that, in the example above, data is a function which returns an object literal (as opposed to being an object literal itself). This is so that each instance of the component receives its own data object and doesn’t have to share one global instance with all other instances.
There are several ways to define a component template. Above we are using a template literal, but we could also use a <script tag> marked with text/x-template or an in-DOM template. You can read more about the different ways of defining templates here.
Single-file Components
In more complex projects, global components can quickly become unwieldy. In such cases, it makes sense to craft your application to use single-file components. As the name suggests, these are single files with a .vue extension, which contain a <template>, <script> and <style> section.
For our example above, an App component might look like this:
<template> <div id="app"> <my-counter></my-counter> </div> </template> <script> import myCounter from './components/myCounter.vue' export default { name: 'app', components: { myCounter } } </script> <style></style>
And a MyCounter component might look like this:
<template> <div></div> </template> <script> export default { name: 'my-counter', data() { return { count: 0 } } } </script> <style></style>
As you can see, when using single-file components, it’s possible to import and use these directly within the components where they’re needed.
In this guide, I’ll present all of the examples using the Vue.component() method of registering a component.
Using single-file components generally involves a build step (for example, with Vue CLI). If this is something you’d like to find out more about, please check out “A Beginner’s Guide to Vue CLI” in this Vue series.
Passing Data to Components Via Props
Props enable us to pass data from a parent component to child component. This makes it possible for our components to be in smaller chunks to handle specific functionalities. For example, if we have a blog component we might want to display information such as the author’s details, post details (title, body and images) and comments.
We can break these into child components, so that each component handles specific data, making the component tree look like this:
<BlogPost> <AuthorDetails></AuthorDetails> <PostDetails></PostDetails> <Comments></Comments> </BlogPost>
If you’re still not convinced about the benefits of using components, take a moment to realize how useful this kind of composition can be. If you were to revisit this code in the future, it would be immediately obvious how the page is structured and where (that is, in which component) you should look for which functionality. This declarative way of composing an interface also makes it much easier for someone who isn’t familiar with a codebase to dive in and become productive quickly.
Since all the data will be passed from the parent component, it can look like this:
new Vue({ el: '#app', data() { return { author: { name: 'John Doe', email: '[email protected]' } } } })
In the above component, we have the author details and post information defined. Next, we have to create the child component. Let’s call the child component author-detail. So our HTML template will look like this:
<div id="app"> <author-detail :owner="author"></author-detail> </div>
We’re passing the child component the author object as props with the name owner. It’s important to note the difference here. In the child component, owner is the name of the prop with which we receive the data from the parent component. The data we want to receive is called author, which we’ve defined in our parent component.
To have access to this data, we need to declare the props in the author-detail component:
Vue.component('author-detail', { template: ` <div> <h2></h2> <p></p> </div> ´, props: ['owner'] })
We can also enable validation when passing props, to make sure the right data is being passed. This is similar to PropTypes in React. To enable validation in the above example, change our component to look like this:
Vue.component('author-detail', { template: ` <div> <h2></h2> <p></p> </div> `, props: { owner: { type: Object, required: true } } })
If we pass the wrong prop type, you’ll see an error in your console that looks like what I have below:
"[Vue warn]: Invalid prop: type check failed for prop 'text'. Expected Boolean, got String. (found in component <>)"
There’s an official guide in the Vue docs that you can use to learn about prop validation.
See the Pen Vue Componets - Props by SitePoint (@SitePoint) on CodePen.
The post A Beginner’s Guide to Working With Components in Vue appeared first on SitePoint.
by Kingsley Silas via SitePoint https://ift.tt/2XrymCO
0 notes
myrtlecornish · 6 years ago
Text
From React to Vue: Re-Vue-sable Components
From React to Vue: Re-Vue-sable Components
For many developers, the most beloved part of any modern front-end framework is the ability to create clear and modular components. React took off like a storm by celebrating its “Just JavaScript” roots, bringing with it a simple but robust API for composing components together into advanced user interfaces. Today, React is not the only option for this style of development. Whereas React delegates design patterns to the developer, Vue.js comes prepackaged with a suite of APIs for creating powerful, reusable components. By leveraging these APIs, any developer can produce a robust Vue.js application.
Vue.js 2.x has two primary approaches for introducing reusability beyond components: mixins and slots. There are a few other options with their own use cases, such as custom directives and JSX inside render functions, but we’ll focus on mixins and slots, as they’ll be applicable to a majority of use cases.
If you’d like to play with any of the examples below, check out my CodeSandbox!
If the <template> keyword is new to you, it essentially takes the place of React’s render function. Check out single file components in Vue.js for some more details.
Mixins
One of the most immediate reuse concerns with components is that different components will often require identical blocks of code. Utility and helper functions can offload a good part of that, but there comes a point where code is reliant on component lifecycle or properties, and copying code really is the most valid solution. Mixins are a programmatic way of doing just that, spreading one block of component-aware code across multiple components. Any option that a component may have, so too can a mixin, be it a method, a computed property, or even a data object. Keeping a functional code block in one place brings some other advantages, such as potentially reducing developer overhead and refactor complexity.
HelloWorldMixin.js
// Mixins are just JavaScript objects const HelloWorldMixin = { computed: { helloWorld() { return 'Hello from Vue.js!'; }, }, }; export default HelloWorldMixin;
HelloWorld.vue
<template> <div> <!-- Hello from Vue.js! --> <p></p> </div> </template> <script> import HelloWorldMixin from 'path/to/HelloWorldMixin.js'; export default { mixins: [HelloWorldMixin] }; </script>
Pure vs. Impure Mixins
There are a couple approaches to mixins. One option is to use them almost as a form of abstract class. For instance, you can create methods that require some property on the component but leave it up to the component to determine how that property is computed. The approach I tend to prefer, however, is creating a pure mixin, one where any required dependencies are kept within the mixin. This kind of encapsulation transforms a mixin into a plug-and-play piece of code. Keeping that code isolated can also be handy when writing tests. Properly testing a mixin often requires creating mock components, and a pure mixin’s detachment from the component means you can test without relying on component internals.
const ImpureMixin = { computed: { helloImpurity() { // There is no guarantee that the component will have this key return `I sure hope my component has ${this.importantProperty}`; }, }, }l const PureMixin = { data() { return { // Instead, include any expected keys within the mixin importantProperty: 'the required value!', }; }, computed: { helloPurity() { // Now we can expect our mixin to work in its default form return `I know my component will have ${this.importantProperty}`; }, }, };
Mixin Override
Vue.js combines mixin options with the component options in the order they appear in the mixins array. While great for composing functionality, this can lead to one common oversight. Conflicting mixin values will be overwritten by whichever is further downstream. In addition, the component will win any conflicts with a mixin.
AllMixins.js
const FirstMixin = { computed: { hello() { return 'Hello from the first mixin'; }, goodbye() { return 'Goodbye from the first mixin'; }, }, }; const SecondMixin = { computed: { hello() { return 'Hello from the second mixin'; }, }, }; export default { FirstMixin, SecondMixin };
CollidingMixins.vue
<template> <div> <!-- Hello from the second mixin --> <p></p> <!-- Goodbye from the component --> <p></p> </div> </template> <script> import { FirstMixin, SecondMixin } from 'path/to/AllMixins.js'; export default { // FirstMixin's `hello` property is overridden by `SecondMixin` mixins: [FirstMixin, SecondMixin], computed: { // Component takes precedence goodbye() { return 'Goodbye from the component'; }, }, }; </script>
Slots
While mixins are great at sharing behavior, they’re not well-suited for two other common features of reusable components: markup and styling. While mixins can technically include a template option, combining markup is finicky, so Vue.js will simply replace it on collision. That’s where slots come in. React developers may recognize the slot API as akin to the children props pattern, and practically, they’d be right. Components with a slot invert control back to the parent component for rendering children.
Below, the components with slots will be called providers, and the components using providers will be called consumers.
Cardify.vue (provider)
<template> <div class="card__container"> <slot></slot> </div> </template>
Using Cardify.vue (consumer)
<template> <cardify> <!-- Any child elements will be injected into the slot --> <p>Hello world!</p> </cardify> </template>
Many reusable providers follow this pattern, housing specific logic and markup internally, but deferring to the consumer for what actually appears. One classic example is a generic card component that handles styling and some logic regarding selection, while leaving the actual content to the consumer. Vue.js slots come with a few other tools, such as support for default content, but two features in particular really expand their flexibility: named slots and scoped slots.
Named slots
Adding the name attribute to a slot grants some additional control for rendering the slot. The provider is able to modify the named slot without directly affecting the consumer’s implementation, while the consumer is able to specify which slots it wants to use. As an example, imagine you have a component that exposes a series of named slots for rendering inputs. The consumer component could take advantage of those names to control the order of those inputs in the source markup, avoiding a lot of in-line template logic and duplicated markup. That flexibility goes the other way as well, allowing the provider to change how they wrap specific slots without requiring change by the consumer. This specificity does come at a cost, however: the named slot will no longer blindly render children. Either the consumer must name their desired slots, or the provider must include a default slot.
CardifyWithName.vue
<template> <div class="card__container"> <slot name="header"></slot> <slot name="content"></slot> </div> </template>
Using CardifyWithName.vue
<template> <cardify-with-name> <!-- Name the slots to be used --> <p slot="header">Hello world!</p> <p slot="content">Check out my fancy named slots</p> <!-- Will not appear! --> <p>Where am I?</p> </cardify-with-name> </template>
Scoped slots
Another pattern commonly used in React is the render props pattern. At first glance, slots have one significant downside when compared to JSX. Render functions frequently reference child properties, as the child is the one invoking the function, typically with its props and/or state. Templates, and by extension slots, are scoped at compilation, and trying to reference child properties in-line will result in failure. Vue.js does support JSX, but it also has a template-based solution in scoped slots, an equally flexible alternative.
CardifyWithScope.vue
<template> <div class="card__container"> <!-- Give props to slots like any other component --> <slot :title="title"></slot> </div> </template> <script> export default { data() { return { title: 'Inside of CardifyWithScope!' }; }, }; </script>
Using CardifyWithScope.vue
<template> <cardify-with-scope> <p>Hello world!</p> <!-- Give the slot scope a name --> <p slot-scope="insideComponent"> <!-- All props given to the slot are now available --> </p> </cardify-with-scope> </template>
By adding scope to a slot, we are able to create valid declarations in the consumer, while relying on the provider to hand it the actual data. Once the scope is declared, it can be referenced within the slot’s scope. To really drive home how closely this mirrors render props, slot scopes even support in-line destructuring (and defaulting, should you need).
Using CardifyWithScope.vue
<template> <cardify-with-scope> <p>Hello world!</p> <!-- Just like JSX --> <p slot-scope="{ title }"> </p> </cardify-with-scope> </template>
Summary
One of the greatest strengths of Vue.js is how much it works to reduce developer workload. React is awesome because of how generic its API is, but Vue.js leverages its more opinionated environment to provide you a simpler workflow from top to bottom. Single-file components, plugins, and a fantastic CLI provide seamless project initialization, while mixins and slots provide convenient APIs for modularizing your UI into flexible components. An ever growing number of web developers have been considering Vue.js, and many of us at Big Nerd Ranch are fans. If you’ve got any questions about Vue.js, or maybe you have even better ideas than the above, post a comment!
From React to Vue: Re-Vue-sable Components published first on https://johnellrod.weebly.com/
0 notes
mbaljeetsingh · 7 years ago
Text
Laravel + Vue.js AdminPanel Generator
News / May 11, 2018
Laravel + Vue.js AdminPanel Generator
Laravel and Vue.js are often used together. With more tools on these technologies are released, here’s one of them – presenting to you Vue+Laravel Admin Panel Generator.
Disclaimer: I’m the founder and one of the developers of this tool, and also Laravel-only generator QuickAdminPanel, but the goal in this article is not only to present you the product, but explain what it generates, and how Vue + Laravel work together. Also, you will find an example project with source available on Github.
How does the generator work?
For those who prefer video, here’s a quick demo:
youtube
Now, let’s look at it with more details.
Step 1. You create your panel without coding, just adding menu items and fields.
Step 2. At any point, you can view the generated code, file by file.
Step 3. Then you download the code and install it – locally or on your remote server, with these commands:
composer install php artisan key:generate php artisan migrate --seed php artisan passport:install
Of course, your .env file should be configured at that point.
And then, on the front-end:
npm install npm run dev
Step 4. That’s it; you have your panel.
Step 5. The most important thing: you can change the code however you want, it’s pure Laravel+Vue, without our generator’s package as a dependency. That’s the main difference from packages like Voyager or Laravel Backpack (which are both excellent, by the way!).
What are we generating – structure of the project
After you download the project, you see something like this:
Generated Code: Back-end Laravel
Let’s first analyze the back-end Laravel part, which serves as API:
Here’s routes/api.php file:
Route::group(['prefix' => '/v1', 'middleware' => ['auth:api'], 'namespace' => 'Api\V1', 'as' => 'api.'], function () { Route::post('change-password', 'ChangePasswordController@changePassword')->name('auth.change_password'); Route::apiResource('roles', 'RolesController'); Route::apiResource('users', 'UsersController'); Route::apiResource('companies', 'CompaniesController'); Route::apiResource('employees', 'EmployeesController'); });
You can see apiResource for every CRUD, and also one separate POST for changing the password.
Controllers are namespaces under Api/V1, so here’s our app/Http/Controllers/Api/V1/CompaniesController.php:
namespace App\Http\Controllers\Api\V1; use App\Company; use App\Http\Controllers\Controller; use App\Http\Resources\Company as CompanyResource; use App\Http\Requests\Admin\StoreCompaniesRequest; use App\Http\Requests\Admin\UpdateCompaniesRequest; use Illuminate\Http\Request; class CompaniesController extends Controller { public function index() { return new CompanyResource(Company::with([])->get()); } public function show($id) { $company = Company::with([])->findOrFail($id); return new CompanyResource($company); } public function store(StoreCompaniesRequest $request) { $company = Company::create($request->all()); return (new CompanyResource($company)) ->response() ->setStatusCode(201); } public function update(UpdateCompaniesRequest $request, $id) { $company = Company::findOrFail($id); $company->update($request->all()); return (new CompanyResource($company)) ->response() ->setStatusCode(202); } public function destroy($id) { $company = Company::findOrFail($id); $company->delete(); return response(null, 204); } }
We have a typical resourceful Controller, with one exception – Resources classes, which have been available since Laravel 5.5.
In our case, every resource is a simple conversion to an array, here’s a file app/Http/Resources/Company.php
namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class Company extends JsonResource { /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return parent::toArray($request); } }
But you can extend it, adding your logic on top – see more examples here and here.
Finally, Laravel Passport protects all the routes – when installing the project, you need to run this:
php artisan passport:install
As an overall back-end result, every Controller is responsible for that specific CRUD operations called to the API, from Vue.js front-end.
Generated Code: Front-end Vue.js
Now, let’s take a look at front-end part. The main file for this is resources/client/assets/js/app.js, where we initiate the Vue and some libraries:
// ... window.Vue = require('vue') Vue.prototype.$eventHub = new Vue() import router from './routes' import store from './store' import Datatable from 'vue2-datatable-component' import VueAWN from 'vue-awesome-notifications' import vSelect from 'vue-select' import datePicker from 'vue-bootstrap-datetimepicker' import VueSweetalert2 from 'vue-sweetalert2' import 'eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.css' Vue.use(Datatable) Vue.use(VueAWN, { position: 'top-right' }) Vue.use(datePicker) Vue.use(VueSweetalert2) Vue.component('back-buttton', require('./components/BackButton.vue')) Vue.component('bootstrap-alert', require('./components/Alert.vue')) Vue.component('event-hub', require('./components/EventHub.vue')) Vue.component('vue-button-spinner', require('./components/VueButtonSpinner.vue')) Vue.component('v-select', vSelect) moment.updateLocale(window.app_locale, { week: { dow: 1 } }) const app = new Vue({ data: { relationships: {}, dpconfigDate: { format: window.date_format_moment }, dpconfigTime: { format: window.time_format_moment }, dpconfigDatetime: { format: window.datetime_format_moment, sideBySide: true } }, router, store }).$mount('#app')
Next, every CRUD has its own set of components:
For showing the data table, we’re using vue2-datatable-component – here’s full code of resources/clients/assets/components/cruds/Companies/Index.vue:
<template> <section class="content-wrapper" style="min-height: 960px;"> <section class="content-header"> <h1>Companies</h1> </section> <section class="content"> <div class="row"> <div class="col-xs-12"> <div class="box"> <div class="box-header with-border"> <h3 class="box-title">List</h3> </div> <div class="box-body"> <div class="btn-group"> <router-link :to="{ name: xprops.route + '.create' }" class="btn btn-success btn-sm"> <i class="fa fa-plus"></i> Add new </router-link> <button type="button" class="btn btn-default btn-sm" @click="fetchData"> <i class="fa fa-refresh" :class="{'fa-spin': loading}"></i> Refresh </button> </div> </div> <div class="box-body"> <div class="row" v-if="loading"> <div class="col-xs-4 col-xs-offset-4"> <div class="alert text-center"> <i class="fa fa-spin fa-refresh"></i> Loading </div> </div> </div> <datatable v-if="!loading" :columns="columns" :data="data" :total="total" :query="query" :xprops="xprops" /> </div> </div> </div> </div> </section> </section> </template> <script> import { mapGetters, mapActions } from 'vuex' import DatatableActions from '../../dtmodules/DatatableActions' import DatatableSingle from '../../dtmodules/DatatableSingle' import DatatableList from '../../dtmodules/DatatableList' import DatatableCheckbox from '../../dtmodules/DatatableCheckbox' export default { data() { return { columns: [ { title: '#', field: 'id', sortable: true, colStyle: 'width: 50px;' }, { title: 'Name', field: 'name', sortable: true }, { title: 'Description', field: 'description', sortable: true }, { title: 'Actions', tdComp: DatatableActions, visible: true, thClass: 'text-right', tdClass: 'text-right', colStyle: 'width: 130px;' } ], query: { sort: 'id', order: 'desc' }, xprops: { module: 'CompaniesIndex', route: 'companies' } } }, created() { this.$root.relationships = this.relationships this.fetchData() }, destroyed() { this.resetState() }, computed: { ...mapGetters('CompaniesIndex', ['data', 'total', 'loading', 'relationships']), }, watch: { query: { handler(query) { this.setQuery(query) }, deep: true } }, methods: { ...mapActions('CompaniesIndex', ['fetchData', 'setQuery', 'resetState']), } } </script> <style scoped> </style>
Quite a lot of code, isn’t it? Of course, it could be more straightforward, but we tried to follow the official documentation and best practices, generating code for the cases that could be extended for bigger projects.
Next, we can take a look at Create.vue:
<template> <section class="content-wrapper" style="min-height: 960px;"> <section class="content-header"> <h1>Companies</h1> </section> <section class="content"> <div class="row"> <div class="col-xs-12"> <form @submit.prevent="submitForm"> <div class="box"> <div class="box-header with-border"> <h3 class="box-title">Create</h3> </div> <div class="box-body"> <back-buttton></back-buttton> </div> <bootstrap-alert /> <div class="box-body"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" name="name" placeholder="Enter Name" :value="item.name" @input="updateName" > </div> <div class="form-group"> <label for="description">Description</label> <textarea rows="3" class="form-control" name="description" placeholder="Enter Description" :value="item.description" @input="updateDescription" > </textarea> </div> </div> <div class="box-footer"> <vue-button-spinner class="btn btn-primary btn-sm" :isLoading="loading" :disabled="loading" > Save </vue-button-spinner> </div> </div> </form> </div> </div> </section> </section> </template> <script> import { mapGetters, mapActions } from 'vuex' export default { data() { return { // Code... } }, computed: { ...mapGetters('CompaniesSingle', ['item', 'loading']) }, created() { // Code ... }, destroyed() { this.resetState() }, methods: { ...mapActions('CompaniesSingle', ['storeData', 'resetState', 'setName', 'setDescription']), updateName(e) { this.setName(e.target.value) }, updateDescription(e) { this.setDescription(e.target.value) }, submitForm() { this.storeData() .then(() => { this.$router.push({ name: 'companies.index' }) this.$eventHub.$emit('create-success') }) .catch((error) => { console.error(error) }) } } } </script> <style scoped> </style>
Edit and Show components for the CRUD are pretty similar, so won’t discuss them here.
In addition to that Vue code, there are many small details and helpers like Sweet Alert, Notifications, Datepickers, and setting/getting relationships data for the forms. I guess I will leave it for you to analyze.
Notice: The choice of Vue.js libraries is pretty subjective, and it was the most challenging part of the project – to choose the Vue libraries to trust. Ecosystem still lacks standards, or 100% trusted open-source – a lot of movement in the market, some libraries are better supported than others. So it’s always hard to guess, and the best libraries will probably change with time, or new ones will appear.
That’s the end of a quick overview of Vue+Laravel QuickAdminPanel, try it out here: https://vue.quickadminpanel.com
Finally, here’s the source of a demo-project with two CRUDs: Companies and Customers.
I hope our generator will not only save you time on writing code but also show you how Vue can work with Laravel. Our way of structuring this code is not the only way, and you can structure your code differently, but we tried our best to stick to standards.
via Laravel News https://ift.tt/2wzPFV6
0 notes
iyarpage · 7 years ago
Text
A Lovely Spring View: Spring Boot & Vue.js
It´s time to shed some light on the integration of Vue.js with the popular Java Enterprise framework Spring Boot! Both frameworks are shining stars in their respective domain – but how could they be set up together properly? What is a practical project structure and build process? How does the development work locally and how is the app deployed? Let´s elucidate these questions!
Vue.js looks like a great choice!
I have to admit: I am not a frontend developer! I really like to play around with “backend stuff” like Spring Boot, web and microservices, automating whole infrastructures with Vagrant, Packer, Ansible and Docker – while I just wanted to scale my apps with Spring Cloud, Docker Swarm and Traefik…
But wait! Isn´t there a frontend I need to build from time to time?! Yeah, there aren´t that many occasions, but sometimes I have to get my hands dirty with some JavaScript code.
Tumblr media
Especially when you are giving lectures at university and try to digitize some old paper processes with your students. And if you ask our CTO, this “backend developer” thing won´t be around much longer…
Tumblr media
Alright then, we need to choose the “right” frontend framework – having nearly no clue. The last web app I built was based on Angular 1 – and it felt like a good choice! I loved the coding experience and after a day of training, I felt able to write awesome frontends… But now it’s two years later and I heard rumors that there was a complete rewrite of Angular (2), a new kid in town from Facebook (React) and lots of ES201x stuff, dependency managers, linters and more. Whew! But if I get my colleagues right, Vue.js isn´t the worst choice! Just take a look at all those posts that have been written in our blog this spring (especially if you need a deeper dive into Vue.js):
Rapid prototyping with Vue.js Vue.js – it’s simple until you make it complicated Vue.js & React – JavaScript UI Frameworks im Vergleich
Also, other projects move from one of the other big frameworks like Angular to Vue.js. Some of the main points are Vue.js’ much flatter learning curve and the higher coding speed compared to Angular and React. And the introduction phrase sounds really great:
Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is very easy to pick up and integrate with other libraries or existing projects.
Project setup
So I think it could be a good idea to invest some time into Vue.js. As you may know, I strive to write quite comprehensible blog posts – you can find every bit inside the example project on GitHub. So let´s have a quick look into the project´s structure. The project uses Maven´s Multi Module capabilities to achieve a clean setup:
Tumblr media
The pom.xml in the project´s root folder spring-boot-vuejs therefore contains the two modules backend and frontend:
frontendbackend
Spring Boot 2.0.x backend
The easiest way to create a new Spring Boot app is – as Josh Long really likes to emphasize – start dot spring dot io! Just initialize a Spring Boot app with the Web dependency and place the generated zip´s contents into the backend folder. There are only two things I had to change for the Vue.js integration. First the spring-boot-starter-parent has to move to our parent pom.xml in the root directory.
Second – and this is a key concept of our project setup here – we need to copy the generated HTML, JavaScript & CSS to a resources folder where it can be served by Spring Boot´s embedded Webserver later easily. This could be done with the maven-resources-plugin:
maven-resources-plugincopy Vue.js frontend contentgenerate-resourcescopy-resourcessrc/main/resources/publictrue${project.parent.basedir}/frontend/target/diststatic/index.html
It just takes the results from the frontend build process (placed in /frontend/target/dist) and places them into /backend/src/main/resources/public folder. With this a simple java -jar backend-0.0.1-SNAPSHOT.jar will run our Spring Boot App and serve all the frontend assets. But first of all let´s build a frontend to serve!
Just for later needs we also create a simple RESTful Service in BackendController.java and use the great testing tooling from rest-assured together with Spring Boot to test our services inside the BackendControllerTest.class:
@RunWith(SpringRunner.class) @SpringBootTest( classes = SpringBootVuejsApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT ) public class BackendControllerTest { @LocalServerPort private int port; @Test public void saysHello() { when() .get("http://localhost:" + port + "/api/hello") .then() .statusCode(HttpStatus.SC_OK) .assertThat() .body(is(equalTo(BackendController.HELLO_TEXT))); }
Vue.js 2.5.x frontend
If you want to reproduce every step mentioned here, you´ll need a working Node.js installation as a prerequisite. Just use your preferred package manager and install it – like brew install node on a Mac. We´ll also need the Vue.js command line interface vue-cli, which could be installed with the help of npm, the Node.js Package Manager:
npm install --global vue-cli
To initialize a project skeleton for Vue.js, we only have to execute the following inside the frontend directory:
vue init webpack frontend
This command results in some questions that require answers:
Tumblr media
The generated skeleton is a great starting point for your Vue.js experiments. If you want to learn more about installing Vue.js, just head over to the docs.
The frontend-maven-plugin
The easiest way to handle every bit of the quite complex frontend build process with npm, node.js, ESLint, Karma, webpack and so on is to just use the frontend-maven-plugin. If you know Maven, that’s everything you need! Just add the plugin to the frontend’s pom.xml and you can use your well-known Maven commands:
com.github.eirslettfrontend-maven-plugin${frontend-maven-plugin.version}install node and npminstall-node-and-npmv9.11.1npm installnpmgenerate-resourcesinstallnpm run buildnpmrun build
The configuration of the frontend-maven-plugin ensures that the correct Node.js and npm versions are installed – with Node.js version > 4.0.0 the plugin takes care of the corresponding npm version, so you don´t have to explicitly configure it here. Additionally it installs all of our frontend dependencies (via npm install) and runs the full frontend build process with npm run build.
Tell webpack to output build contents to /target
The standard Node.js way is to create a dist directory for builds which contain the minified source code of our web application. But as we use Maven here, we need to have everything in the target directory. Therefore we need to change the generated frontend/config/index.js and replace the following lines:
index: path.resolve(__dirname, '../dist/index.html'), assetsRoot: path.resolve(__dirname, '../dist'),
with
index: path.resolve(__dirname, '../target/dist/index.html'), assetsRoot: path.resolve(__dirname, '../target/dist'),
First app run
Now we already have everything in place to fire up our Spring Boot powered Vue.js application! Just enter the project’s repository and let Maven do its job inside the root spring-boot-vuejs directory:
mvn clean install
This will build our whole app and we can simply do a:
java -jar backend/target/backend-0.0.1-SNAPSHOT.jar
Now let´s open our browser and hit http://localhost:8088/. That´s it, our app should now look like this:
Tumblr media
Development process
Although we now have our app successfully running for the first time, we need to take a closer look at how the development process could work with Spring Boot and Vue.js integrated. Because we don´t really want to wait for the full Maven/npm build to complete and wait for our app to be fired up with java -jar until we see a simple frontend element changed in the browser!
We want to get much faster feedback if we change frontend code. Luckily the webpack-dev-server comes to the rescue! This piece of magic will just update and build every change through all the parts of our JavaScript build chain instantly – and is pre-configured in our setup out of the box. The only thing to start the webpack-dev-server is to switch over to the frontend directory and run:
npm run dev
That’s it! Just try it yourself. The command automatically opens your browser. Just enter the Vue.js source in frontend/src and change something. It will instantly be visible
Tumblr media
Another neat tool is the Vue.js browser extension. Just install it into your Chrome or Firefox and you should have a deep look into your Vue components inside the Browser´s development tools:
Tumblr media
Accessing Spring Boot REST services from Vue.js frontend
As we´re integrating Vue.js with Spring Boot, we for sure want to call some of those nice RESTful web services our Spring Boot backend provides us with. There are many libraries to access web services that one can use with Vue.js. One of them is axios, which is a quite popular Promise API based HTTP client with a huge number of GitHub stars. To use axios in our project, we only have to install the npm dependency:
npm install axios --save
Calling a REST service with Axios is simple. Go into the script area of your component (e.g. in the Service.vue) and add:
import axios from 'axios' data () { return { response: [], errors: [] } }, callRestService () { axios.get(`api/hello`) .then(response => { // JSON responses are automatically parsed. this.response = response.data }) .catch(e => { this.errors.push(e) }) } }
Now inside the template area of your Vue.js component you can request a service call with the callRestService() method – and access the response data accordingly:
CALL Spring Boot REST backend service
Get out of the same-origin policy (SOP) hell
The HTTP calls with axios are working fine – except when we try to use them in our local fast feedback development process with the webpack-dev-server. Why? Because if we start the webpack-dev-server via npm run dev, it will serve our web application on http://localhost:8080. But our Spring Boot REST backend runs on http://localhost:8088! As a core concept of web application security, the same-origin policy (SOP) will then prevent our Vue.js frontend from accessing its Spring Boot backend – resulting in SOP errors.
One way to solve this problem is to use the Cross Origin Resource Sharing Protocol (CORS). Although this isn´t a big deal with both axios and Spring Boot, there´s a much more nifty solution. Thanks to my colleague Daniel who pointed me to the nice proxying feature of webpack-dev-server, we don´t need to configure all the complex CORS stuff!
According to the Vue.js Webpack Template the only thing we need to configure is a Proxy for our webpack-dev-server requests. This can easily be done in the frontend/config/index.js – right inside the dev.proxyTable field:
dev: { ... proxyTable: { // proxy all webpack dev-server requests starting with /api to our Spring Boot backend (localhost:8088) '/api': { target: 'http://localhost:8088', changeOrigin: true } },
With this configuration in place, the webpack-dev-server uses the really handy http-proxy-middleware to proxy all frontend requests with a preceding /api from http://localhost:8080 to http://localhost:8088 – including changing the Origin HTTP header accordingly. Remember that our Spring Boot REST services are configured to serve those requests to /api on class level:
@RestController() @RequestMapping("/api") public class BackendController { @RequestMapping(path = "/hello") public @ResponseBody String sayHello() { return "Hello from Spring Boot Backend!"; }
The proxyTable configuration is finally used in the frontend/build/dev-server.js to configure the proxyMiddleware. We don´t need to change anything here, but I wanted to show the usage of the http-proxy-middleware:
// proxy api requests Object.keys(proxyTable).forEach(function (context) { var options = proxyTable[context] if (typeof options === 'string') { options = { target: options } } app.use(proxyMiddleware(options.filter || context, options)) })
Is the app ready for deployment?
OK, now I can´t really conceal that I love that Continuous Delivery stuff.
Tumblr media
So no example project is complete as long as it´s not running anywhere “productively”.
As you may already have found out, the example project has a live deployment configuration for Heroku: With every push into the master branch, our Spring Boot powered Vue.js app is built by TravisCI and deployed to:
https://spring-boot-vuejs.herokuapp.com
In the course of setting up the example project I really fell in love with the great Automatic deploys feature of Heroku and Heroku Pipelines. If the “Wait for CI to pass before deploy” checkbox is selected, we get a fully working pipeline and are able to demonstrate that our example project is also ready for deployment! Thanks again for pointing me to this great platform, Benedikt!
And that´s it!
Now we found a nice way to integrate Vue.js and Spring Boot. As both are really popular frameworks in their respective domain, I hope this introduction is helpful to some of you folks. If you manage to work through all the points shown in this post, you will have a solid project setup that can be used for both local development and deployment – mainly because both Vue.js and Spring Boot bring in such great features. And as “old school” Maven is supported by nearly every platform, this setup is ready for anything you can imagine. Let me know about your great Spring Boot powered Vue.js apps!
Der Beitrag A Lovely Spring View: Spring Boot & Vue.js erschien zuerst auf codecentric AG Blog.
A Lovely Spring View: Spring Boot & Vue.js published first on https://medium.com/@koresol
0 notes
philleepflorence-blog · 7 years ago
Link
In this article, we'll take a look at the biggest and best JavaScript frameworks around, and explore how to get the best out of them for your next projects. We'll look at Vue.js, React, AngularJS, Polymer and Aurelia – you can use the drop-down menu above to jump to the framework you want to explore first.
Most of these frameworks are open source projects, too, so you can dig in and see how they work – or even contribute yourself.
Vue.js
Tumblr media
Best for:
Beginners
Lightweight applications with a small footprint
Vue.js is a progressive JavaScript framework for building user interfaces. An open source project (see the GitHub repo here), its ideal for beginners. The main library is focused on the view layer and all templates are valid HTML, making it easy to pick up. In the following two mini-tutorials, we'll walk through how to use Vue to manage multiple data stores, and speed up the first load to improve your site's performance.
01. Manage state with Vue
As with any component-based library, managing state in Vue can be tricky. While the application is small, it’s possible to keep things in sync by emitting events when values change. However, this can become brittle and prone to errors as the application grows, so it may be better to start out with a more centralised solution.
If you’re familiar with Flux and Redux, Vuex works in much the same way. State is held in one centralised location and is linked to the main Vue application. Everything that happens within the application is reflected somewhere within that state. Components can select what information is relevant to them and be notified if it changes, much like if it was part of its internal state.
A Vuex store is made up of four things: the state, getters, mutations and actions. The state is a single object that holds all the necessary data for the entire application. The way this object gets structured depends on the project, but would typically hold at least one value for each view.
Getters work like computed properties do inside components. Their value is derived from the state and any parameters passed into it. They can be used to filter lists without having to duplicate that logic inside every component that uses that list.
The state cannot be edited directly. Any updates must be performed through mutation methods supplied inside the store. These are usually simple actions that perform one change at a time. Each mutation method receives the state as an argument, which is then updated with the values needed to change.
Mutations need to be synchronous in order for Vuex to understand what has changed. For asynchronous logic – like a server call – actions can be used instead. Actions can return Promises, which lets Vuex know that the result will change in the future as well as enabling developers to chain actions together.
To perform a mutation, they have to be committed to the store by calling commit()and passing the name of the mutation method required. Actions need to be dispatched in a similar way with dispatch().
It’s good practice to have actions commit mutations rather than commit them manually. That way, all updating logic is held together in the same place. Components can then dispatch the actions directly, so long as they are mapped using the mapActions() method supplied by Vuex.
To avoid overcomplicating things, the store can also be broken up into individual modules that look after their own slice of the state. Each module can register its own state, getters, mutations and actions. State is combined between each module and grouped by their module name, in much the same way as combineReducers() works within Redux.pport.
02. Explore lazy load routes
By default, the entire contents of the application end up inside one JavaScript file, which can result in a slow page load. A lot of that content is never used on the first screen the user visits. Instead it can be split off from the main bundle and loaded in as and when needed.
Vue makes this process incredibly simple to set up, as vue-router has built-in support for lazy loading.
Vue supports using dynamic imports to define components. These return Promises, which resolve to the component itself. The router can then use that component to render the page like normal. These work alongside code splitting built in to Webpack, which makes it possible to use features like magic comments to define how components should be split.
React
Tumblr media
Best for:
Sites and applications with complex view logic
Quick prototypes with a low barrier to entry
Launched in 2013, React is maintained by Facebook and Instagram, alongside a community of developers. It's component-based and declarative, and you can also use it to power mobile apps via React Native.
Here, we'll explain how to keep your code clean by separating your concerns, move contents outside of the root component, and ensure errors don't destabilise your application.
Use container and presentational components
As with any project, it's important to keep a separation of concerns. All React applications start off simple. As they grow, it can be tempting to keep adding logic to the same few components. In theory, this simplifies things by reducing the number of moving parts. When problems arise, however, these large components become prone to errors that are difficult to debug.
React and JSX encourage the creation on multiple small components to keep things as simple as possible. While breaking the interface down into smaller chunks can help with organisation, having a further separation between how a component works and what it looks like provides greater flexibility.
Container and presentational components are special names given to this separation. The container's job is to manage state and deal with interfacing with other parts of the application such as Redux, while the presentational component deals solely with providing the interface.
A container component will often be in charge of a small section of the UI, like a tweet. It will hold all the workings of that component – from storing state, like the number of likes, to the methods required for interaction, such as a mechanism for liking that tweet.
If the application makes use of external libraries, include at this point. For example, Redux's connect method would provide the container with a way of dispatching actions to the store without worrying the presentational component.
Containers will never render their 
own UI and will instead render 
another component – the presentational component.
This component will be passed props that detail all the information needed to render the view. If it needs to provide interactivity, the container will then pass down methods for this as well, which can be called like any other method.
Having this separation encourages developers to keep things as simple 
as possible. If a container is starting 
to grow too large, it makes it easy 
to break off into a smaller set 
of components.
If the inner workings of a component, such as its state, needs to change, this technique allows the presentational component to remain unaffected. This also means this component can be used somewhere else in the application without needing to adjust how it functions. As long as it keeps getting served the same data it will continue to work.
Render with portals
React 16 introduced the ability to return lots of different types of data from a component. While previously it had to be either a single component or 'null', the latest version allows strings, numbers, arrays and a new concept called 'portals'.
The return value of a render() method decides what React displays, which is shown at that point in the component hierarchy. Portals allow React to render any of these return types outside of the component they were called from.
These can be other parts of the page completely separate from the main application. They still form part of React and work just the same as any component, but are able to reach outside of the normal confines of 
the root container.
A typical use case of this technique would be to trigger modal windows. To get correct positioning, overlay 
and accessibility requirements out 
of a modal it ideally needs to sit as a direct descendant of the <body>. The problem is, the root of a single page application will likely take up that position. Components managing modals will either need to trigger something in the root component, or render it out of place.
Here the Modal component returns a portal. The create function for it takes two arguments – what needs to be rendered and where it should render it. The second parameter is a regular DOM node reference, rather than anything specific to React.
In this example, it references a <div> at the top of the DOM tree that is a sibling of the main app container. It is possible to target any node, visible or not, as with any JavaScript. To use it, another component can summon Modal just like any other component. It will 
then display its contents in the targeted node.
Because React events are synthetic, they are capable of bubbling up from the portal contents to the containing component, rather than the DOM node they are rendered in. In the modal example, this means that 
the summoning component can 
also handle its state, such as its visibility or contents.
Establish error boundaries
Unhandled errors can cause havoc in a JavaScript application. Without catching them as they happen, methods can stop executing half way. This can cause unpredictable behaviour if the user continues and is a bad experience all around.
Previous versions of React did not cope with these situations well. If an error occurred in a nested component, it would leave its parents in limbo. The component state object would be stuck in the middle of performing an operation that could end up locking up the interface.
As of version 16, the way React handles errors has changed. Now an error inside any component would unmount the entire application. While that would stop issues arising with an unstable state, it doesn't lend itself well to a good user experience.
To avoid this, we can create a special component called an error boundary to ring-fence parts of the application from the rest. Any errors that happen inside children of the boundary will not cause issues to those outside of it.
Error boundaries work a lot like typical catch blocks in JavaScript. When an error occurs somewhere inside the component tree, it will be caught by the componentDidCatch() method, which receives the error thrown along with a stack trace. When that gets called it is an opportunity to replace the tree with a fresh interface – typically an error message.
Since it only renders its children, this component 
can wrap others 
to catch any errors that happen within it. The components chosen for this will vary by application, but error boundaries can be placed wherever they are needed, including inside other boundaries.
Error boundary components shouldn't be too complicated. If an error occurs inside of a boundary, it will bubble up to the next boundary up. Failing that, it will unmount the whole application as usual.
AngularJS
Tumblr media
Best for:
Large projects in need of structure
Applications with lots of changing data
AngularJS is an open source frontend web application framework developed by Google. It offers declarative templates with data-binding, MVW, MVVM, MVC, and dependency injection, all implemented using pure client-side JavaScript.
Here, we'll show you how to use AngularJS to create reusable code blocks known as custom decorators, serve content to your users quicker, and create performant and easy to control animations with ease.
Create custom decorators
TypeScript is a superset that sits on top of JavaScript. It supplies features such as static typing, classes and interfaces that are lacking in the native language. This means that when creating large applications developers can get feedback on how best to work with external code and avoid unnecessary bugs.
Angular is built exclusively on top of TypeScript, so it is important to understand how to utilise it correctly. Combining the strengths of both provides a solid foundation for the application as it grows. There are not many better techniques to demonstrate this than with decorators.
Decorators are special functions designed to supply behaviour to whatever it is applied to. Angular makes extensive use of them to provide hints to the compiler, like with @Component on classes or @Input on properties.
The aim is to make these functions as reusable as possible and are often used to provide utility functions, such as logging. In the example above, @ClassLogger is supplied to a component to log to the console when certain lifecycle hooks are fired. This could be applied to any component to track its behaviour.
The ClassLogger example above returns a function, which enables us 
to customise the behaviour of the decorator as it is created. This is known as the decorator factory pattern, which is used by Angular 
to create its own decorators.
To apply a decorator, it needs to be positioned just before what it is decorating. Because of the way they are designed, decorators can be stacked on top of each other, including Angular's own. TypeScript will chain these decorators together and combine their behaviours.
Decorators are not just limited to classes. They can be applied to properties, methods and parameters inside of them as well. All of these follow similar patterns, but are slightly different in their implementations.
This is an example of a plain method decorator. These take three arguments – the object targeted, the name of the method, and the descriptor that provides details on its implementation. By hooking into the value of that descriptor we can replace the behaviour of the method based on 
the needs of the decorator.
Build platform-level animations
Animations are a great way to introduce a friendly side to an interface. But trying to control animations in JavaScript can be problematic. Adjusting dimensions like height is bad for performance, while toggling classes 
can quickly get confusing. The Web Animations API is a good approach, but working with it inside Angular can be tricky.
Angular provides a module that enables components to be animated by integrating with the properties already within the class. It uses a syntax similar to CSS-based animations, which gets passed in as component metadata.
Each animation is defined by a 'trigger' – a grouping of states and transition effects. Each state is a string value that, when matched, applies the associated styles to the element. The transition values define different ways the element should move between those states. In this example, once the value bound to hidden evaluates to true, the element will shrink out of view.
Two other special states are also defined: void and *. The void state relates to a component that was not in the view at the time and can be used to animate it in or out. The wildcard * will match with any state and could be used to provide a dimming effect while any transition occurs.
Inside the template, the trigger is bound to a value within the component that represents the state. As that value changes, as does the state of the animation.
That bound value can be supplied either as a plain property or as the output of a method, but the result needs to evaluate into a string that can be matched against an animation state.
These animations also provide callbacks such as when they start 
or stop. This can be useful for removing components that are 
no longer visible.
Serve content quicker with server rendering
HTML parsers struggle with JavaScript frameworks. Web crawlers are often not sophisticated enough to understand how Angular works, so they only see a single, blank element and not the whole application.
By rendering the application on the server, it sends down an initial view for the users to look at while Angular and the rest of the functionality downloads in the background. Once the application arrives, it silently picks up from where the server left off.
The tools needed to achieve this in Angular are now a native part of the platform as of version 4. With a bit of set up, any application can be server rendered with just a few tweaks.
Both server and browser builds need their own modules, but share a lot of common logic. Both need a special version of BrowserModule, which allows Angular to replace the contents on-screen when it loads in. The server also needs ServerModule to generate the appropriate HTML.
Servers also need their own entry points where they can bootstrap their unique behaviours as necessary. That behaviour depends on the app, but will also likely mirror much of the main browser entry point.
If using the CLI, that also needs to be aware of how to build the project for the server by pointing to the new entry point. This can be triggered by using the "--app" flag when building 
for the server.
The application is now ready to be server rendered. Implementations will vary based on the server technology used, but the base principles remain the same. For example, Angular provide an Express engine for Node, which can be used to populate the index page based on the request sent. All the server needs to do is serve that file. Server rendering is a complex subject with many edge cases (look here for more information).
Polymer
Tumblr media
Best for:
Combining with other platforms and frameworks
Working with JavaScript standards
Polymer is a lightweight library designed to help you take full advantage of Web Components. Read on to find out how to use it to create pain-free forms, bundle your components to keep requests low and sizes small, and finally how to upgrade to the latest Polymer release: 3.0.
Work with forms
Custom elements are part of the browser. Once they are set up they work like any native element would do on the page. Most of the time, Polymer is just bridging the gap between now and what custom elements will be capable of in the future, along with bringing features like data binding.
One place where custom elements shine is their use as form inputs. Native input types in browsers are limited at best, but provide a reliable way of sending data. In cases where a suitable input isn't available – such as in an autocomplete field, for example – then custom elements can  provide a suitable drop-in solution.
As their work is performed within the shadow DOM, however, custom input values will not get submitted alongside regular form elements like usual. Browsers will just skip over them without looking at their contents.
One way around this is to use an <iron-form> component, which is provided by the Polymer team. This component wraps around an existing form and will find any values either as a native input or custom element. Provided a component exposes a form value somewhere within the element, it will be detected and sent like usual.
In cases where a custom element does not expose an input, it's still possible to use that element within a form, provided it exposes a property that can be bound to.
If <my-input> exposes a property like "value" to hook into we can pull that value out as part of a two-way binding. The value can then be read out into a separate hidden input as part of the main form. It can be transformed at this point into a string to make it suitable for form transmission. Forms not managed by Polymer that would need to make use of these bindings, the Polymer team also provide a <dom-bind>component to automatically bind these values.
Bundle components
One of Polymer's biggest advantages is that components can be imported and used without any need for a build process. As optimised as these imports may be, each component requires a fresh request, which slows things down. While HTTP/2 would speed things up in newer browsers, those who do not support it will have a severely degraded experience. For those users, files should be bundled together.
If a project is set up using the Polymer CLI, bundling is already built in to the project. By running polymer build, the tool will collect all components throughout the project and inline any subcomponents they use.
This cuts down on requests, removes unnecessary comments and minifies to reduce the file size. It also has the added benefit of creating separate bundles for both ES5 and ES2015 to support all browsers.
Outside of Polymer CLI, applications can still be bundled using the separate Polymer Bundler library. This works much like the CLI, but is more of a manual process. By supplying a component, it will sift through the imports of the file, 
inline their contents, and output a bundled file.
Polymer Bundler has a few separate options to customise the output. For example, developers can choose to keep comments or only inline specific components.
Upgrade to Polymer 3.0
The philosophy behind Polymer is to 'use the platform': instead of fighting against browser features, work with them to make the experience better for everyone. HTML imports are a key part of Polymer 2, but are being removed from the web components specification moving forward.
Polymer 3.0 changes the way that components are written to work with more established standards. While no breaking changes are made with the framework itself, it's important 
to know how the syntax changes 
in this new version.
First thing to note is that Polymer is migrating away from Bower as a package manager. To keep up with the way developers work, npm will become the home of Polymer, as well as any related components in the future.
To avoid using HTML imports, components are imported as JavaScript modules using the existing standardised syntax.
The major difference inside a component is that the class is now exported directly. This enables the module import <script> tag to 
work correctly. Any other components can be included by using ES2015 import statements within this file.
Finally, templates have been moved into the class and work 
with template literals. A project by the Polymer team called lit-html is working to provide the same flexibility as <template> tags 
along with the efficiency of 
selective DOM manipulation.
Aurelia
Tumblr media
Best for:
Simple applications with 
little setup
Developing alongside 
web standards
Aurelia is a JavaScript client framework for web, mobile and desktop. It's written with next-gen ECMAScript, integrates with Web Components and has no external dependencies.
Read on for two mini-tutorials, showing you how to change how properties display value and function, and how to use Aurelia to check values in forms.
01. Use value converters
Sometimes, when developing components, the values being stored do not lend themselves well to being displayed in a view. A Date object, for example, has an unhelpful value when converted to a string, which requires developers to make special conversion methods just to show values correctly.
To get around this problem, Aurelia provides a mechanism to use classes to change values, known as value converters. These can take any kind of value, apply some kind of processing to it, and output that changed value in place of the original.
They work similar to pipes in Angular or filters in template languages like Twig.
Most will be one way – from the model to the view. But they can also work the other way. The same logic applies, but by using fromView instead of toView, values can be adjusted before they are returned back to the model.
A good use-case for this would be to format user input directly from the bind on the element. In this example, it will capitalise every word that is entered, which may be useful for a naming field.
They can also be chained together, which encourages the creation of composable converters that can have different uses across the application. One converter could filter an array of values, which then passes to another that sorts them.
Converters can also be given simple arguments that can alter the way they behave. Instead of creating different converters to perform similar filtering, create one that takes the type of filter to be performed as an argument. While only one argument is allowed, they can be chained together to achieve the same effect.
02. Try framework-level form validation
Validation is an important part of any application. Users need to be putting the correct information into forms for everything to work correctly. If they do not, they should be warned of the fact as early as possible.
While validation can often be a tricky process, Aurelia has support for validating properties built right into the framework. As long as form values are bound to class properties, Aurelia can check that they are correct whenever it makes sense to the application.
Aurelia provides a ValidationController, which takes instructions from the class, looks over the associated properties and supplies the template with any checks that have failed.
Each controller requires a single ValidationRules class that defines what's to be checked. These are all chained together, which enables the controller to logically flow through the checks dependant on the options that are passed.
Each ruleset begins with a call to ensure(), which takes the name of 
the property being checked. Any commands that follow will apply 
to that property.
Next are the rules. There are plenty of built-in options like required() or email() that cover common scenarios. Anything else can use satisfies(), which takes a function that returns either a Boolean or a Promise that passes or fails the check.
After the rules come any customisations of that check, for example the error message to display. Rules provide default messages, but these can be overridden if necessary.
Finally, calling on() applies the ruleset to the class specified. If it is being defined from within the constructor of the class, it can be called with this instead.
By default, validation will be fired whenever a bound property's input element is blurred. This can be changed to happen either when the property changes, or it can be triggered manually.
0 notes
programmingbiters-blog · 7 years ago
Photo
Tumblr media
New Post has been published on http://programmingbiters.com/build-a-reusable-autocomplete-component-with-vue-2-1-part-2/
Build a Reusable Autocomplete Component with Vue 2.1 - part 2
In this second, and final, part, we’ll add the necessary keyboard and mouse interactions, implement selecting an option, and filter the displayed options depending on what’s typed in in the input.
Closing or opening the options dropdown
Right now, we can see that the options dropdown is always open. This, obviously, isn’t the way it should be. The dropdown should be shown only when the user types something in the input. And it should be closed when the user clears the input, presses escape key, or blurs the input.
The first step to accomplish this is to add isOpen in the component’s data list and set its default value to false.
data () return isOpen: false
With that being added, use that boolean on the dropdown container, ul.options-list, using v-show, like this:
<ul v-show="isOpen" class="options-list" >
Now we get to the events part. We need to register three events on the input element – @input, @keyup.esc, and @blur.
<input class="input is-large" placeholder="Search..." @input="onInput($event.target.value)" @keyup.esc="isOpen = false" @blur="isOpen = false" >
For @keyup and @blur, everything is ready. But for @input, we have to define a new method called onInput accepting the value of the input.
methods: onInput (value) this.isOpen = !!value
What that method does is check whether the entered text, after casting it to boolean, is empty or not. And using that value we close or open the dropdown.
Highlighting options with keyboard’s up/down arrow keys
Our next task is to let users select options using the keyboard’s arrow keys.
We first need to keep track of the position of the highlighted option. Thus, add highlightedPosition to component’s data list.
data () return isOpen: false, highlightedPosition: 0
We’re going to use a dynamic class, named .highlighted, to show the currently highlighted option. And we decide whether the class should be applied to the option by comparing the option’s index with highlightedPosition.
So, modify the option element in the component like this:
<li v-for="(option, index) in options" :class=" 'highlighted': index === highlightedPosition " >
Now we’ve dynamically styled the currently highlighted option, let’s add the two keyboard events to move selection onto other options. We’ll add them on the input, along with the other events.
<input class="input is-large" placeholder="Search..." @input="onInput($event.target.value)" @keyup.esc="isOpen = false" @blur="isOpen = false" @keydown.down="moveDown" @keydown.up="moveUp" >
In this case, we prefer to use @keydown over @keyup to allow for continuous event firing while the key is being pressed. In other words, the selection would keep moving up/down as long as the corresponding arrow key is pressed.
Next, implement the two handlers, like so:
moveDown () if (!this.isOpen) return this.highlightedPosition = (this.highlightedPosition + 1) % this.options.length , moveUp () if (!this.isOpen) return this.highlightedPosition = this.highlightedPosition - 1 < 0 ? this.options.length - 1 : this.highlightedPosition - 1
Selecting an option
So far, the user can highlight options, but can’t choose them. This is going to be our next step.
Let’s start by adding @keydown event, for the enter key, on our input. This will make our input look like this:
<input v-model="keyword" class="input is-large" placeholder="Search..." @input="onInput($event.target.value)" @keyup.esc="isOpen = false" @blur="isOpen = false" @keydown.down="moveDown" @keydown.up="moveUp" @keydown.enter="select" >
When the user selects an option, the component should fetch the option from options list using highlightedPosition, fill the input with the full title of the selected option, close the dropdown, and fire an event letting the parent know about it.
Here’s how its implementation should look like:
select () const selectedOption = this.options[this.highlightedPosition] this.keyword = selectedOption.title this.isOpen = false this.$emit('select', selectedOption)
Everything should work fine except for that this.keyword line, because we haven’t declared that variable yet.
So, add it with empty default value:
data () return isOpen: false, highlightedPosition: 0, keyword: ''
Then, add a two-way binding for that value using v-model on the text input.
<input v-model="keyword" <!-- ... --> >
Before you move on to the next section, you may want to check if the custom event, select, work as expected. You can do so, by listening to it from the parent and log what gets selected.
<autocomplete-input :options="options" @select="onOptionSelect" >
Log the selected option like so:
methods: onOptionSelect (option) console.log('Selected option:', option)
Support mouse interactions
So far, we’ve been using the keyboard to interact with our component. The mouse is, of course, not less important; so, let’s support it. And the great thing is that we can do so with, literally, two lines of code!
All you have to do is change the highlightedPosition when the mouse hovers over an option and call the select method when it clicks on it.
<li v-for="(option, index) in options" :class=" 'highlighted': index === highlightedPosition " @mouseenter="highlightedPosition = index" @mousedown="select" >
One important note to make here is that we used @mousedown instead of @click. The reason for that is because @mousedown gets fired before @blur, so we make sure that the option is selected before the dropdown is closed when the input is blurred.
Enabling filtering
Finally, let’s make our component a real autocomplete input by filtering the options according to what the user has typed in.
Doing so only requires two small steps. First, add this computed property:
computed: fOptions () const re = new RegExp(this.keyword, 'i') return this.options.filter(o => o.title.match(re))
After that, replace all occurrences of options with fOptions. To make it easier on you, here are the places you need to replace:
<li v-for="(option, index) in options".
moveDown, moveUp, and select methods.
With that being done, your input should filter the displayed options properly.
One last small thing to do, to improve our component, is reset the highlighted position each time the user changes the text in the input. And you can do so, simply, by adding this.highlightedPosition = 0 in onInputmethod:
onInput (value) this.isOpen = !!value this.highlightedPosition = 0
In closing
I have to say it. I have never seen any easier way to create a reusable piece of functionality than it is with Vue. And the more time passes, the easier it becomes – like that scoped slot feature.
I hope this two-part series has taught you something new. And as always, I’m more than happy to hear your feedback and answer your questions in the comments section.
0 notes
mablebarber49-blog · 8 years ago
Text
Nikki Erlick
Seven Incredible Realities Concerning gel.
The road to Pan-Africanism should be actually inter-generational. Tony Elumelu Inquire any sort of business owner and also most, otherwise all, will definitely inform you that they are actually steered through passion. Mam Richard Branson I wait exactly what I have claimed just before - there is actually no magic formula for wonderful company lifestyle. Right now, I assume the more vital part is actually the Not Do" expression - making note of the interesting fact that this is co-equal with Do." The majority of my specialist work lifestyle, I failed to definitely believe or symbolize that equality in the means I came close to points. This is actually to state that the energy is actually wonderful adequate to introduce in to a period of officially indigenizing psychology in Ghana. This is to state that once the suitable supranatural and also epistemological questions are raised as well as addressed, Black psychology would certainly have reached the level from assistance through a paradigm" (Watson, 1967, p. 435) and also that would end up being qualitatively unlike its Western side psychological science. This study is going to be posted by trusted African and also Western authors, and also commonly shared within Africa and its Diaspora. The industry relatively self-referentially is actually pattern awareness from time-series profiles to show power effectiveness issues in buildings. Permit's acquire one point out of the way to begin with: there is no such factor as reverse racism" unless you are (racistly) considering the planet as white". Practical and also emotional assistance for females business owners in the process is vital - yet inner strength and also decision are going to make the difference in between an ambition remaining a desire or even coming true. Access to meeting events included in the rate of a convention successfully pass - ₤ 17 per day, or ₤ 27 for a weekend break elapsed, under 12s go into for free with an accompanying ticket holding parent/guardian, as well as price cuts are offered for cosplayers as well as Breeze Card holders. I left myself, placed the emphasis back on me in the situation of just how could I be useful to others and also out of just how might others assist me. If I am actually not alright, every thing else isn't really either. You will definitely obtain consistent start-up help coming from TFF, and also increase unique perks from companions, like intros to world-leading gas systems. Growing musicians must see the free of charge sample manuscript right here, pull their personal variation of this, as well as carry their attempts to the profile sessions being actually secured at the 2000 ADVERTISEMENT desk at the Thought Blister Witty Con on Sunday 15th Nov. The displaying performers have been attracting, painting, printing and also creating non stop for the final 2 years as well as are excited regarding this possibility to exhibit their skills as component of the Thought Bubble festival. Sunlight 24 Sept, Brodrick Hallway, Leeds Urban area Museum, Centuries Square, Leeds LS2 8BH, 13:30 -14:30, Any ages, Free. Among its lots of systems, Centro Fox supports the advancement of leaders dedicated to offering their neighborhoods in Mexico and also Latin America. While many scholastic financial experts perform decline such 'long-wave' ideas, historians of Kondratiev surges do reveal that cycles from innovation, capital war, financial investment and crisis exist historically, as well as follow waveforms like Kondratiev with outstanding accuracy. His publications as well as assisted mind-calming exercise systems describe reflection method in such commonsensical, applicable, and engaging conditions that mindfulness meditation practice has actually ended up being a way of living for lots of individuals. Notion Blister Event 2015// Reside Event// 1000-1700. SelfMadeHero: A Many years of Comics// Board// 1030. Working off of world or even any type of accessible aid, in challenging ailments, taught him how you can beat any sort of problem and lead folks to attain their expert and also individual goals. While I rejoice I did factors my technique the first 3 years, I'm even better that I took a pro like Andrew in when I performed. There are actually today business people which are concentrating on things like just how our team remain healthy, just how our team eat, just how our team get around, exactly how we manage electricity, just how our experts know and also a lot of other seriously important aspects of the lifestyles from billions.
What Will gel Be Like In The Upcoming HALF A CENTURY?
Thur 13 Nov, VUE Cinema, The Lighting, Leeds, 1300 (116 minutes), ₤ 8 (₤ 6 concession), simply see for tickets. Below in Europe I would highlight the circumstances of the Roma, that are socially omitted, marginalised and jobless initially- as well as that's very clear that in the context from the recession- programs made to handle their social omission have actually been actually reduced or eliminated entirely in some nations.
The 10 Keys You Will certainly Certainly never Learn about gel.
Basically, we are happy in any case, are deciding to commit private of anyone else, and also accept the business owner on that they want to have actually included. At the center of the prophetic as well as amazing hurricane sit four figures, convivially conversing concerning comics. Huge Idea acts as a backbone agency to a network of plans as well as companies across the city from Dallas.simply click the up coming web site, you could call us at our own web-site. jpg" width="283" />
0 notes
suzanneshannon · 5 years ago
Text
Let’s Make a Vue-Powered Monthly Calendar
Have you ever seen a calendar on a webpage and thought, how the heck did they did that? For something like that, it might be natural to reach for a plugin, or even an embedded Google Calendar, but it’s actually a lot more straightforward to make one than you might think. Especially when we use the component-driven power of Vue.
I’ve set up a demo over at CodeSandbox so you can see what we’re aiming for, but it’s always a good idea to spell out what we’re trying to do:
Create a month view grid that displays the days of the current month
Display dates from the previous and next months to so the grid is always full
Indicate the current date
Show the name of the currently selected month
Navigate to the previous and next month
Allow the user to navigate back to the current month with a single click
Oh, and we’ll build this as a single page application that fetches calendar dates from Day.js, a super light utility library.
Step 1: Start with the basic markup
We’re going to jump straight into templates. If you’re new to Vue, Sarah’s introduction series is a nice place to start. It’s also worth noting that I’ll be linking to the Vue 2 docs throughout this post. Vue 3 is currently in beta and the docs for it are subject to change.
Let’s start with creating a basic template for our calendar. We can outline our markup as three layers where we have:
A section for the calendar header. This will show components with the currently selected month and the elements responsible for paginating between months.
A section for the calendar grid header. A table header that holds a list containing the days of the week, starting with Monday.
The calendar grid. You know, each day in the current month, represented as a square in the grid.
Let’s write this up in a file called CalendarMonth.vue. This will be our main component.
<!-- CalendarMonth.vue --> <template>   <!-- Parent container for the calendar month -->   <div class="calendar-month">          <!-- The calendar header -->     <div class="calendar-month-header"       <!-- Month name -->       <CalendarDateIndicator />       <!-- Pagination -->       <CalendarDateSelector />     </div>     <!-- Calendar grid header -->     <CalendarWeekdays />     <!-- Calendar grid -->     <ol class="days-grid">       <CalendarMonthDayItem />     </ol>   </div> </template>
Now that we have some markup to work with, let’s go one step further and create required components.
Step 2: Header components
In our header we have two components:
CalendarDateIndicator shows the currently selected month.
CalendarDateSelector is responsible for paginating between months.
Let’s start with CalendarDateIndicator. This component will accept a selectedDate property which is a Day.js object that will format the current date properly and show it to the user.
<!-- CalendarDateIndicator.vue --> <template>   <div class="calendar-date-indicator"></div> </template> <script> export default {   props: {   selectedDate: {     type: Object,     required: true   } },   computed: {     selectedMonth() {       return this.selectedDate.format("MMMM YYYY");     }   } }; </script>
That was easy. Let’s go and create the pagination component that lets us navigate between months. It will contain three elements responsible for selecting the previous, current and next month. We’ll add an event listener on those that fires the appropriate method when the element is clicked.
<!-- CalendarDateSelector.vue --> <template>   <div class="calendar-date-selector">     <span @click="selectPrevious">﹤</span>     <span @click="selectCurrent">Today</span>     <span @click="selectNext">﹥</span>   </div> </template>
Then, in the script section, we will set up two props that the component will accept:
currentDate allows us to come back to current month when the “Today” button is clicked.
selectedDate tells us what month is currently selected.
We will also define methods responsible for calculating the new selected date based on the currently selected date using the subtract and add methods from Day.js. Each method will also $emit an event to the parent component with the newly selected month. This allows us to keep the value of selected date in one place — which will be our CalendarMonth.vue component — and pass it down to all child components (i.e. header, calendar grid).
// CalendarDateSelector.vue <script> import dayjs from "dayjs"; export default {   name: "CalendarDateSelector",   props: {     currentDate: {       type: String,       required: true     },     selectedDate: {       type: Object,       required: true     }   },   methods: {     selectPrevious() {       let newSelectedDate = dayjs(this.selectedDate).subtract(1, "month");       this.$emit("dateSelected", newSelectedDate);     },     selectCurrent() {       let newSelectedDate = dayjs(this.currentDate);       this.$emit("dateSelected", newSelectedDate);     },     selectNext() {       let newSelectedDate = dayjs(this.selectedDate).add(1, "month");       this.$emit("dateSelected", newSelectedDate);     }   } }; </script>
Now, let’s go back to the CalendarMonth.vue component and use our newly created components.
To use them we first need to import and register the components, also we need to create the values that will be passed as props to those components:
today properly formats today’s date and is used as a value for the “Today” pagination button.
selectedDate is the  currently selected date (set to today’s date by default).
The last thing we need to do before we can render the components is create a method that’s responsible for changing the value of selectedDate. This method will be fired when the event from the pagination component is received.
// CalendarMonth.vue <script> import dayjs from "dayjs"; import CalendarDateIndicator from "./CalendarDateIndicator"; import CalendarDateSelector from "./CalendarDateSelector"; export default {   components: {     CalendarDateIndicator,     CalendarDateSelector   },   data() {     return {       selectedDate: dayjs(),       today: dayjs().format("YYYY-MM-DD")     };   },   methods: {     selectDate(newSelectedDate) {       this.selectedDate = newSelectedDate;     }   } }; </script>
Now we have everything we need to render our calendar header:
<!-- CalendarMonth.vue --> <template>   <div class="calendar-month">     <div class="calendar-month-header">       <CalendarDateIndicator         :selected-date="selectedDate"         class="calendar-month-header-selected-month"       />       <CalendarDateSelector         :current-date="today"         :selected-date="selectedDate"         @dateSelected="selectDate"       />     </div>   </div> </template>
This is a good spot to stop and see what we have so far. Our calendar header is doing everything we want, so let’s move forward and create components for our calendar grid.
Step 3: Calendar grid components
Here, again, we have two components:
CalendarWeekdays shows the names of the weekdays.
CalendarMonthDayItem represents a single day in the calendar.
The CalendarWeekdays component contains a list that iterates through the weekday labels (using the v-for directive) and renders that label for each weekday. In the script section, we need to define our weekdays and create a computed property to make it available in the template and cache the result to prevent us from having to re-calculate it in the future.
// CalendarWeekdays.vue <template>   <ol class="day-of-week">     <li v-for="weekday in weekdays" :key="weekday" > </li>   </ol> </template> 
 <script> const WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; export default {   name: 'CalendarWeekdays',   computed: {     weekdays() {       return WEEKDAYS     }   } } </script>
Next is CalendarMonthDayItem. It’s a list item that receives a day property that is an object, and a boolean prop, isToday, that allows us to style the list item to indicate that it’s the current date. We also have one computed property that formats the received day object to our desired date format (D, or the numeric day of the month).
// CalendarMonthDayItem.vue <template>   <li     class="calendar-day"     :class="{       'calendar-day--not-current': !isCurrentMonth,       'calendar-day--today': isToday     }"   >     <span></span>   </li> </template> 
 <script> import dayjs from "dayjs"; export default {   name: "CalendarMonthDayItem",   props: {     day: {       type: Object,       required: true     },     isCurrentMonth: {       type: Boolean,       default: false     },     isToday: {       type: Boolean,       default: false     }   },   computed: {     label() {       return dayjs(this.day.date).format("D");     }   } }; </script>
OK, now that we have these two components, let’s see how we can add them to our CalendarMonth component.
We first need to import and register them. We also need to create a computed property that will return an array of objects representing our days. Each day contains a date property and isCurrentMonth property.
// CalendarMonth.vue <script> import dayjs from "dayjs"; import CalendarMonthDayItem from "./CalendarMonthDayItem"; import CalendarWeekdays from "./CalendarWeekdays"; 
 export default {   name: "CalendarMonth",   components: {     // ...     CalendarMonthDayItem,     CalendarWeekdays   },   computed: {     days() {       return [         { date: "2020-06-29", isCurrentMonth: false },         { date: "2020-06-30", isCurrentMonth: false },         { date: "2020-07-01", isCurrentMonth: true },         { date: "2020-07-02", isCurrentMonth: true },         // ...         { date: "2020-07-31", isCurrentMonth: true },         { date: "2020-08-01", isCurrentMonth: false },         { date: "2020-08-02", isCurrentMonth: false }       ];     }   } }; </script>
Then, in the template, we can render our components. Again, we use the v-for directive to render the required number of day elements.
<!-- CalendarMonth.vue --> <template>   <div class="calendar-month">     <div class="calendar-month-header">       // ...     </div>     <CalendarWeekdays/>     <ol class="days-grid">       <CalendarMonthDayItem         v-for="day in days"         :key="day.date"         :day="day"         :is-today="day.date === today"       />     </ol>   </div> </template>
OK, things are starting to look good now. Have a look at where we are. It looks nice but, as you probably noticed, the template only contains static data at the moment. The month is hardcoded as July and the day numbers are hardcoded as well. We will change that by calculating what date should be shown on a specific month. Let’s dive into the code!
Step 4: Setting up current month calendar
Let’s think how we can calculate the date that should be shown on a specific month. That’s where Day.js really comes into play. It provides all the data we need to properly place dates on the correct days of the week for a given month using real calendar data. It allows us to get and set anything from the start date of a month to all the date formatting options we need to display the data.
We will:
Get the current month
Calculate where the days should be placed (weekdays)
Calculate the days for displaying dates from the previous and next months
Put all of the days together in a single array
We already have Day.js imported in our CalendarMonth component. We’re also going to lean on a couple of Day.js plugins for help. WeekDay helps us set the first day of the week. Some prefer Sunday as the first day of the week. Other prefer Monday. Heck, in some cases, it makes sense to start with Friday. We’re going to start with Monday.
The WeekOfYear plugin returns the numeric value for the current week out of all weeks in the year. There are 52 weeks in a year, so we’d say that the week starting January 1 is the the first week of the year, and so on.
Here’s what we put into CalendarMonth.vue to put all of that to use:
// CalendarMonth.vue <script> import dayjs from "dayjs"; import weekday from "dayjs/plugin/weekday"; import weekOfYear from "dayjs/plugin/weekOfYear"; // ... 
 dayjs.extend(weekday); dayjs.extend(weekOfYear); // ...
That was pretty straightforward but now the real fun starts as we will now play with the calendar grid. Let’s stop for a second a think what we really need to do to get that right.
First, we want the date numbers to fall in the correct weekday columns. For example, July 1, 2020, is on a Wednesday. That’s where the date numbering should start.
If the first of the month falls on Wednesday, then that means we’ll have empty grid items for Monday and Tuesday in the first week. The last day of the month is July 31, which falls on a Friday. That means Saturday and Sunday will be empty in the last week of the grid. We want to fill those with the trailing and leading dates of the previous and next months, respectively, so that the calendar grid is always full.
Tumblr media
Adding dates for the current month
To add the days of the current month to the grid, we need to know how many days exist in the current month. We can get that using the daysInMonth method provided by Day.js. Let’s create a computed property for that.
// CalendarMonth.vue computed: {   // ...   numberOfDaysInMonth() {       return dayjs(this.selectedDate).daysInMonth();   } }
When we know that, we create an empty array with a length that’s equal to number of days in the current month. Then we map() that array and create a day object for each one. The object we create has an arbitrary structure, so you can add other properties if you need them.
In this example, though, we need a date property that will be used to check if a particular date is the current day. We’ll also return a isCurrentMonth value that checks whether the date is in the current month or outside of it. If it is outside the current month, we will style those so folks know they are outside the range of the current month.
// CalendarMonth.vue computed: {   // ...   currentMonthDays() {     return [...Array(this.numberOfDaysInMonth)].map((day, index) => {       return {         date: dayjs(`${this.year}-${this.month}-${index + 1}`).format("YYYY-MM-DD")         isCurrentMonth: true       };     });   }, }
Adding dates from the previous month
To get dates from the previous month to display in the current month, we need to check what the weekday of the first day is in selected month. That’s where we can use the WeekDay plugin for Day.js. Let’s create a helper method for that.
// CalendarMonth.vue methods: {   // ...   getWeekday(date) {     return dayjs(date).weekday();   }, }
Then, based on that, we need to check which day was the last Monday in the previous month. We need that value to know how many days from the previous month should be visible in the current month view. We can get that by subtracting the weekday value from the first day of the current month. For example, if first day of the month is Wednesday, we need to subtract three days to get last Monday of the previous month. Having that value allows us to create an array of day objects starting from the last Monday of the previous month through the end of that month.
// CalendarMonth.vue computed: {   // ...   previousMonthDays() {     const firstDayOfTheMonthWeekday = this.getWeekday(this.currentMonthDays[0].date);     const previousMonth = dayjs(`${this.year}-${this.month}-01`).subtract(1, "month");     const previousMonthLastMondayDayOfMonth = dayjs(this.currentMonthDays[0].date).subtract(firstDayOfTheMonthWeekday - 1, "day").date();     // Cover first day of the month being sunday      (firstDayOfTheMonthWeekday === 0)     const visibleNumberOfDaysFromPreviousMonth = firstDayOfTheMonthWeekday ? firstDayOfTheMonthWeekday - 1 : 6;     return [...Array(visibleNumberOfDaysFromPreviousMonth)].map((day, index) = {       return {         date: dayjs(`${previousMonth.year()}-${previousMonth.month() + 1}-${previousMonthLastMondayDayOfMonth + index}`).format("YYYY-MM-DD"),         isCurrentMonth: false       };     });   } }
Adding dates from the next month
Now, let’s do the reverse and calculate which days we need from the next month to fill in the grid for the current month. Fortunately, we can use the same helper we just created for the previous month calculation. The difference is that we will calculate how many days from the next month should be visible by subtracting that weekday numeric value from seven.
So, for example, if the last day of the month is Saturday, we need to subtract one day from seven to construct an array of dates needed from next month (Sunday).
// CalendarMonth.vue computed: {   // ...   nextMonthDays() {     const lastDayOfTheMonthWeekday = this.getWeekday(`${this.year}-${this.month}-${this.currentMonthDays.length}`);     const nextMonth = dayjs(`${this.year}-${this.month}-01`).add(1, "month");     const visibleNumberOfDaysFromNextMonth = lastDayOfTheMonthWeekday ? 7 - lastDayOfTheMonthWeekday : lastDayOfTheMonthWeekday;     return [...Array(visibleNumberOfDaysFromNextMonth)].map((day, index) => {       return {         date: dayjs(`${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}`).format("YYYY-MM-DD"),         isCurrentMonth: false       };     });   } }
OK, we know how to create all days we need, so let’s use them and merge all days into a single array of all the days we want to show in the current month, including filler dates from the previous and next months.
// CalendarMonth.vue computed: {   // ...   days() {     return [       ...this.previousMonthDays,       ...this.currentMonthDays,       ...this.nextMonthDays     ];   }, }
 Voilà, there we have it! Check out the final demo to see everything put together.
The post Let’s Make a Vue-Powered Monthly Calendar appeared first on CSS-Tricks.
You can support CSS-Tricks by being an MVP Supporter.
Let’s Make a Vue-Powered Monthly Calendar published first on https://deskbysnafu.tumblr.com/
0 notes
suzanneshannon · 6 years ago
Text
Reusable Popovers to Add a Little Pop
A popover is a transient view that shows up on top of a content on the screen when a user clicks on a control button or within a defined area. For example, clicking on an info icon on a specific list item to get the item details. Typically, a popover includes an arrow pointing to the location from which it emerged.
Popovers are great for situations when we want to show a temporary context to get user’s attention when interacting with a specific element on the screen. They provide additional context and instruction for users without having to clutter up a screen. Users can simply close them by clicking the same way they were opened or outside the popover.
We’re going to look at a library called popper.js that allows us to create reusable popover components in the Vue framework. Popovers are the perfect type of component for a component-based system like Vue because they can be contained, encapsulated components that are maintained on their own, but used anywhere throughout an app.
Let’s dig in and get started.
But first: What’s the difference between a popover and tooltip?
Was the name "popover" throwing you for a loop? The truth is that popovers are a lot like tooltips, which are another common UI pattern for displaying additional context in a contained element. There are differences between them, though, so let’s briefly spell them out so we have a solid handle on what we’re building.
Tooltips Popovers Tooltips are meant to be exactly that, a hint or tip on what a tool or other interaction does. They are meant to clarify or help you use the content that they hover over, not add additional content. Popovers, on the other hand, can be much more verbose, they can include a header and many lines of text in the body. Tooltips are typically only visible on hover, for that reason if you need to be able to read the content while interacting with other parts of the page then a tooltip will not work. Popovers are typically dismissible, whether by click on other parts of the page or second clicking the popover target (depending on implementation), for that reason you can set up a popover to allow you to interact with other elements on the page while still being able to read it's content.
Popovers are most appropriate on larger screens and we’re most likely to encounter them in use cases such as:
dropdown menus (navigation menu, custom select)
user onboarding
temporary forms
list item interaction menus
Looking at those use cases, we can glean some requirements that make a good popover:
Reusability: A popover should allow to pass a custom content to the popover.
Dismissibility: A popover should be dismissible by clicking outside of the popover and escape button.
Positioning: A popover should reposition itself when the screen edge is reached.
Interaction: A popover should allow to interact with the content in the popover.
Tumblr media
I created an example to refer to as we go through the process of creating a component.
View Demo
OK, now that we’ve got a baseline understanding of popovers and what we’re building, let’s get into the step-by-step details for creating them using popper.js.
Step 1: Create the BasePopover component
Let’s start by creating a component that will be responsible for initializing and positioning the popover. We’ll call this component BasePopover.vue and, in the component template, we’ll render two elements:
Popover content: This is the element that will be responsible for rendering the content within the popover. For now we use a slot that will allow us to pass the content from the parent component responsible for rendering our popover (Requirement #1: Reusability).
Popover overlay: This is the element responsible for covering the content under the popover and preventing user from interacting with the elements outside the popover. It also allows us to close the popover when clicked (Requirement #2: Dismissibility).
// BasePopover.vue <template> <div> <div ref="basePopoverContent" class="base-popover" > <slot /> </div> <div ref="basePopoverOverlay" class="base-popover__overlay" /> </div> </template>
In the script section of the component:
we import popper.js (the library that takes care of the popover positioning), then
we receive the popoverOptions props, and finally
we set initial popperInstance to null (because initially we do not have any popover).
Let’s describe what the popoverOptions object contains:
popoverReference: This is an object in relation to which the popover will be positioned (usually element that triggers the popover).
placement: This is a popper.js placement option that specifies the where the popover is displayed in relation to the popover reference element (the thing it is attached to)
offset: This is a popper.js offset modifier that allows us to adjust popover position by passing x- and y-coordinates.
import Popper from "popper.js" export default { name: "BasePopover", props: { popoverOptions: { type: Object, required: true } }, data() { return { popperInstance: null } } }
Why do we need that? The popper.js library allows us to position the element in relation to another element with ease. It also does the magic when the popover gets to the edge of the screen an reposition it to be always in user’s viewport (Requirement #3: Positioning)
Step 2: Initialize popper.js
Now that we have a BasePopover component skeleton, we will add few methods that will be responsible for positioning and showing the popover.
In the initPopper method, we will start by creating a modifiers object that will be used to create a Popper instance. We set the options received from the parent component (placement and offset) to the corresponding fields in the modifiers object. All those fields are optional, which is why we first need to check for their existence.
Then, we initialize a new Popper instance by passing:
the popoverReference node (the element to which the popover is pointing: popoverReference ref)
the popper content node (the element containing the popover content: basePopoverContent ref)
the options object
We also set the preventOverflow option to prevent the popover from being positioned outside of the viewport. After initialization we set the popper instance to our popperInstance data property to have access to methods and properties provided by popper.js in the future.
methods: { ... initPopper() { const modifiers = {} const { popoverReference, offset, placement } = this.popoverOptions if (offset) { modifiers.offset = { offset } } if (placement) { modifiers.placement = placement } this.popperInstance = new Popper( popoverReference, this.$refs.basePopoverContent, { placement, modifiers: { ...modifiers, preventOverflow: { boundariesElement: "viewport" } } } ) } ... }
Now that we have our initPopper method ready, we need a place to invoke it. The best place for that is in the mounted lifecycle hook.
mounted() { this.initPopper() this.updateOverlayPosition() }
As you can see, we are calling one more method in the mounted hook: the updateOverlayPosition method. This method is a safeguard used to reposition our overlay in case we have any other elements on the page that have absolute positioning (e.g. NavBar, SideBar). The method is making sure the overlay is always covering the full screen and prevent user from interacting with any element except the popover and overlay itself.
methods: { ... updateOverlayPosition() { const overlayElement = this.$refs.basePopoverOverlay; const overlayPosition = overlayElement.getBoundingClientRect(); overlayElement.style.transform = <code>translate(-${overlayPosition.x}px, -${ overlayPosition.y }px)`; } ... }
Step 3: Destroy Popper
We have our popper initialized but now we need a way to remove and dispose it when it gets closed. There’s no need to have it in the DOM at that point.
We want to close the popover when we click anywhere outside of it. We can do that by adding a click listener to the overlay because we made sure that the overlay is always covering the whole screen under our popover
<template> ... <div ref="basePopoverOverlay" class="base-popover__overlay" @click.stop="destroyPopover" /> ... </template>
Let’s create a method responsible for destroying the popover. In that method we first check if the popperInstance actually exist and if it does we call popper destroy method that makes sure the popper instance is destroyed. After that we clean our popperInstance data property by setting it to null and emit a closePopover event that will be handled in the component responsible for rendering the popover.
methods: { ... destroyPopover() { if (this.popperInstance) { this.popperInstance.destroy(); this.popperInstance = null; this.$emit("closePopover"); } } ... }
Step 4: Render BasePopover component
OK, we have our popover ready to be rendered. We do that in our parent component, which will be responsible for managing the visibility of the popover and passing the content to it.
In the template, we need to have an element responsible for triggering our popover (popoverReference) and the BasePopover component. The BasePopover component receives a popoverOptions property that will tell the component how we want to display it and isPopoverVisible property bound to v-if directive that will be responsible for showing and hiding the popover.
<template> <div> <img ref="popoverReference" width="25%" src="./assets/logo.png" > <BasePopover v-if="isPopoverVisible" :popover-options="popoverOptions" > <div class="custom-content"> <img width="25%" src="./assets/logo.png"> Vue is Awesome! </div> </BasePopover> </div> </template>
In the script section of the component, we import our BasePopover component, set the isPopoverVisible flag initially to false and popoverOptions object that will be used to configure popover on init.
data() { return { isPopoverVisible: false, popoverOptions: { popoverReference: null, placement: "top", offset: "0,0" } }; }
We set popoverReference property to null initially because the element that will be the popover trigger does not exist when our parent component is created. We get that fixed in the mounted lifecycle hook when the component (and the popover reference) gets rendered.
mounted() { this.popoverOptions.popoverReference = this.$refs.popoverReference; }
Now let’s create two methods, openPopover and closePopover that will be responsible for showing and hiding our popover by setting proper value on the isPopoverVisible property.
methods: { closePopover() { this.isPopoverVisible = false; }, openPopover() { this.isPopoverVisible = true; } }
The last thing we need to do in this step is to attach those methods to appropriate elements in our template. We attach the openPopover method to click event on our trigger element and closePopover method to closePopover event emitted from the BasePopover component when the popover gets destroyed by clicking on the popover overlay.
<template> <div> <img ... @click="openPopover" > <BasePopover ... @closePopover="closePopover" > ... </BasePopover> </div> </template>
Having this in place, we have our popover showing up when we click on the trigger element and disappearing when we click outside of the popover.
Step 5: Create BasePopoverContent component
It does not look like a popover though. Sure, it renders content passed to the BasePopover component, but it does so without the usual popover wrapper and an arrow pointing to the trigger element. We could have included the wrapper component in the BasePopover component, but this would made it less reusable and couple the popover to a specific template implementation. Our solution allows us to render any template in the popover. We also want to make sure that the component is responsible only for positioning and showing the content.
To make it look like a popover, let’s create a BasePopoverContent component. We need to render two elements in the template:
an arrow element having a popper.js x-arrow selector needed for the popper.js to properly position the arrow
content wrapper that expose a slot element in which our content will be rendered
<template> <div class="base-popover-content"> <div class="base-popover-content__arrow" x-arrow/> <div class="base-popover-content__body"> <slot/> </div> </div> </template>
Now let’s use our wrapper component in the parent component where we use BasePopover
<template> <div> <img ref="popoverReference" width="25%" src="./assets/logo.png" @click="openPopover" > <BasePopover v-if="isPopoverVisible" :popover-options="popoverOptions" @closePopover="closePopover" > <BasePopoverContent> <div class="custom-content"> <img width="25%" src="./assets/logo.png"> Vue is Awesome! </div> </BasePopoverContent> </BasePopover> </div> </template>
And, there we go!
You can see the popover animating in and out in the example above. We’ve left animation out of this article for the sake of brevity, but you can check out other popper.js examples for inspiration.
You can see the animation code and working example here.
Let’s look at our requirements and see if we didn’t missed anything:
Pass? Requirement Explanation Pass Reusability We used a slot in the BasePopover component that decouples the popover implementation from the content template. This allows us to pass any content to the component. Fail Dismissibility We made it possible to close the popover when clicking outside of it. We still need to make sure we can dismiss the popover by pressing the ESC on the keyboard. Pass Positioning That’s where popper.js solved an issue for us. It not only gave us positioning superpowers, but also takes care of repositioning the popover when it reaches the edge of the viewport. Fail Interaction We have a popover popping in and out, but we do not have any interactions with the popover content yet. As for now, it looks more like a tooltip than popover and could actually be used as a tooltip when it comes to showing and hiding the element. Tooltips are usually shown on hover, so that’s the only change we’d have to make.
Darn, we failed interaction requirement. Adding the interaction is a matter of creating a component (or components) that will be placed in the BasePopoverContent slot. In the example, I created a very simple component with a header and text showing a few Vue style guide rules. By clicking on the buttons, we can interact with the popover content and change the rules, when you get to the last rule the button changes its purpose and serve as a close button for the popover. It’s a lot like the new user welcome screens we see in apps.
We also need to fully meet the dismissibility requirement. We want to hit ESC on the keyboard to close the popover in addition to clicking anywhere outside it. For kicks, we’ll also add an event that proceeds to the next Vue style guide rule when pressing Enter.
We can handle that in the component responsible for rendering the popover content using Vue event key modifiers. To make the events work we need to make sure that the popover is focused when mounted. To do that we add a tabindex attribute to the popover content and a ref that will allow us to access the element in the mounted hook and call focus method on it.
// VueTourPopoverContent.vue <template> <div class="vue-tour-popover-content" ref="vueTourPopoverContent" tabindex="-1" @keydown.enter="proceedToNextStep" @keydown.esc="closePopover" > ... </template ... <script> export default { ... mounted() { this.$refs.vueTourPopoverContent.focus(); } ... } </script>
Wrapping up
And there we have it: a fully functional popover component we can use anywhere in our app. Here are a few things we learned along the way:
Use a popover to expose a small amount of information or functionality. Remember that the content will disappear when user is finished with it.
Consider using popovers instead of temporary views like sidebars. Popovers leave more space for content and are only temporary.
Enable a closure behavior that makes sense based on the popover’s function. A popover should be visible only when needed. If it allows user to make a choice, close the popover as soon as the user makes a decision.
Position popovers onscreen with care. A popover’s arrow should always point directly to the element that triggered it and should never cover the trigger element.
Display one popover on screen at a time. More than one steals attention.
Take care of the popover size. Prevent making it too big but bear in mind that proper use of padding can make things look nice and clean.
If you don't want to dig too deep into the code and you just need the component as it is, you can try out the npm package version of the component.
Hopefully you will find this component useful in your project!
The post Reusable Popovers to Add a Little Pop appeared first on CSS-Tricks.
Reusable Popovers to Add a Little Pop published first on https://deskbysnafu.tumblr.com/
0 notes
nancydsmithus · 6 years ago
Text
SVG Web Page Components For IoT And Makers (Part 2)
SVG Web Page Components For IoT And Makers (Part 2)
Richard Leddy
2019-05-15T13:30:16+02:002019-05-15T15:35:00+00:00
So, we already have ways of dynamically loading a menu of SVG icons made to react by loading panels if we so desire, but the icons were not actual components. We were able to use a simple trick of bringing in the SVG for each icon and passing it into the Vue application. It was simple enough to generate a list of icons, and each icon reacted in a similar way except for small data differences. The data difference made it possible to bind the name of a panel to each icon in such a way that the handler for the icon’s button click could pass it on.
When a panel is loaded in the form of Vue component, everything about the panel and its components has to be loaded, templates, JavaScript, and more. So, the job of just managing loading the panel is bigger than what we have encountered so far in this discussion.
Let’s look at Vue’s way of providing a hook for async loading. The following snippet is from the Vue guide.
Vue.component('async-example', function (resolve, reject) { setTimeout(function () { // Pass the component definition to the resolve callback resolve({ template: '<div>I am async!</div>' }) }, 1000) })
The guide tells us that the setTimeout function is an example of how to use the synchronicity with Vue components. Notice that where before there had been an object as the second parameter to Vue.component, there is now a function, which is referred to as a factory function. Within the resolve callback is a component definition, that would have been the second parameter to Vue.component before.
So, I had to stare at this example a while before it made sense to me. Here is another example, which suits me better:
Vue.component('async-example', function (resolve, reject) { // Vue will call this function and promise itself to handle // it when it gets back with data. // this function can then call a promising object loader // here the 'loader' function is some abstract function. // Most likely the application will use 'fetch' // but it could be something else. loader('/my/resource/on/server.json'). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } );
It seems like the right thing to do to make a more general function to go around this form.
function componentLoader(c_name,resource_url) { Vue.component(c_name, function (resolve, reject) { loader(resource_url). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } ); }
So, in general, to load a component, we would just need a line like the following:
componentLoader('ThermoPanel','./JSON/thermo-panel.json');
So now, just what is the JSON that is being loaded? It can include everything about the component. In this case, as a panel component, it can include thermometers, machine switches, sliders, gauges, and more. While it seemed nicer to keep the components parts on the web page, it may actually work better to use the subcomponent field that is in the longer example for ‘thermo-panel’ that we made before and also for the other similarly constructed panels. The JSON will contain a complete panel structure.
However, if the reader will notice the inclusion of the function call to transformJSONToJSObject, he will understand that JSON might be coded in some way to make transport easier and to make it easier for a server to handle the definition. After all, the definition will include complete SVG templates, function definitions, and other JavaScript expressions. Also, the JSON object may contain more than just the panel definition because some information may simply aid in bookkeeping or validation. So, one can expect that there will be some treatment of the object upon receipt.
As for the encoding, the data coming in from the server may be encoded in a number of ways. Perhaps it will be simply URL encoded. Or more securely, it might be enciphered. For this discussion, we can just use URL encoding.
Some of the tools that are available for creating Vue applications no doubt take care of the JSON transformation. But, this discussion has so far avoided the use of command line tools. This omission is not that bad as we have also used Vue with the minimum of resources, using only one script tag for the referring to the CDN. However, I certainly do recommend looking into the command line tools especially for organizing projects.
When the JSON arrives at the page, given the component is completely assembled with subcomponents, no more work has to be done to fetch the parts. We can make the assumption that all components will come in fully defined for the rest of this discussion. But, assembling complete component hierarchies will require command line tools at some point.
The SVG editing process will also require some work. The SVG editing processes allow a designer to draw a panel and all the components on it. But, each subcomponent has to be identified, called out in a group, or given a place holder. Any approach to using the drawing requires some treatment of the SVG so that Vue component tags can replace the groups or graphic elements. In this way, any artist rendering can become a template. And, the drawn subcomponents will have to be disassembled into templates for Vue subcomponents.
This sort of parsimony is contrary to the workflow of most of the JavaScript frameworks. The frameworks are about assembling pages. But, editing or drawing, results in something already assembled by an artist. In practice, the result of editing does not provide a text file that corresponds directly to a framework component definition.
More about the editing process may be considered in some other discussion. There is a lot to it. But, for now, we have the tools we need in order to load hierarchal components and make them come alive.
The Lazy Application
For our IoT panel construction, we already have a selection bar that responds to searches. And, we have a way of loading components when we need them. We just need to connect up these parts. And, at last, we have to make sure that the panels appear and that they start working when they do.
The lazy loading of panels done by the async code above provides a sketch of an idea. But, thankfully, some people have experimented to find ways of making sure that all kinds of components can be loaded. There is one codepen entry that shows how to update Vue apps with new components of varying types. That is the mechanism that is needed for updating a designated part of the page with different types of panel.
With the ability to add in different kinds of panels and with a simple mechanism to load their definitions, we can, at last, have our panel searching page.
Here is the HTML that we need in our page so that the Vue app can place components in dynamically:
<template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name"></component> </template>
The component tag is a Vue meta tag. See the reference for dynamic components. The properties, special attributes, used for the component tag in this case are is and key. The is attribute exists for dynamic components. And, the key ensures that the new children will have different identities from each other and helps Vue to decide what to draw.
“Children of the same common parent must have unique keys. Duplicate keys will cause rendering errors.”
The template tag will loop through components that are provided in the panelList data field of the application.
So, starting with the application level Vue definition for the icon app, we can make changes to include the panelList in the data elements. (Let’s now call it the panelApp).
var panelApp = new Vue({ el: '#PanelApp', data: { iconList: [ // Where is the data? Still on the server. ], panelList: [ ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: function (pname) { // var url = panelURL(pname); // this is custom to the site. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = decodeURIComponent(text); eval(pHat); // widgdef = object def, must be assignment pHat = widgdef; var pnameHat = pname + pcount++; pHat.name = pnameHat; // this is needed for the key this.panelList.push(pHat); // now it’s there. }).catch( error => { /* handle it */ }); } } });
Besides adding in the panel, goGetPanel is now in a form required for getting a component definition from a database or other store. The server side must be careful about delivering JavaScript code in the correct format. As for what the object looks like coming from the server, we have already seen it. It is the kind of object used as a parameter to Vue.component.
Here is the complete body of the Vue app that provides a menu as a search result and a place to put panels fetched from the server when the user clicks an icon.
<div id="PanelApp"> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: .</p> <button onclick="GetIcons(11)">Find All</button> <button onclick="GetIcons(5)">Find 5 Point</button> <button onclick="GetIcons(6)">Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart" style="padding:4px"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> <div class="entryart" style="padding:4px" > <template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name" :ref="panel.name" ></component> </template> </div> </div>
In the last div, the component tag now has a ref parameter bound to the panel name. The ref parameter allows Vue app to identify which component to update with data and keeps components separate. The ref parameters also allow our application access to the new dynamically loaded components.
In one test version of the panel app, I have the following interval handler:
setInterval(() => { var refall = panelApp.$refs; // all named children that panels for ( var pname in refall ) { // in an object var pdata = refall[pname][0]; // off Vue translation, but it’s there. pdata.temp1 = Math.round(Math.random()*100); // make thermos jump around. pdata.temp2 = Math.round(Math.random()*100); } },2000)
The code provides a little animation, changing thermometers randomly. Each panel has two thermometers, and the app allows the user to keep adding panels. (In the final version, some panels must be thrown away.) The refs are being accessed using panelApp.$refs, a field that Vue creates given the refs information in the component tag.
So, this is what the randomly jumping thermometers look like in one snapshot:
Tumblr media
A collection of animated panels for one type of panel (or component). (Large preview)
Connecting The Panel To The IoT Device
So, the last piece of code is a setInterval test updating thermometers with random values every two seconds. But, what we want to do is read in real data from real machines. In order to do that, we will need some form of communication.
There are a variety of ways. But, let’s use MQTT which is a pub/sub message system. Our SPWA can subscribe to messages from devices at any time. When it gets those messages the SPWA can direct each message to the appropriate data handler for the panel mapped to the device identified in the message.
So, basically what we need to do is replace the setInterval with a response handler. And, that will be for one panel. We probably want to map panels to handlers as they are loaded. And, it is up to the web server to see that the correct mapping is delivered.
Once the web server and the SPWA have the page ready for operation, the web server no longer needs to take care of messaging between the page and the device. the MQTT protocol specifies a routing server to handle pub/sub. A number of MQTT servers have been made. Some of them are open source. One very popular one is Mosquito, and there are a few developed on top of Node.js.
The process for the page is simple. The SPWA subscribes to a topic. One good version of a topic is an identifier for an MCU such as a MAC address or a serial number. Or, the SPWA could subscribe to all temperature readings. But, then the page would have to do the work of filtering the messages from all devices. Publication in MQTT is essentially a broadcast or multicast.
Let’s take a look at how the SPWA will interface with MQTT.
Initializing MQTT On The SPWA
There are several client libraries to choose from. One, for instance, is a MQTT.js. Another is eclipse paho. There are more of course. Let’s use Eclipse Paho since it has a CDN stored version. We just need to add the following line to our page:
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>
The MQTT client has to connect to a server before it can send and receive messages. So, lines setting up the connection also need to be included in the JavaScript. We can add in a function MQTTinitialize which sets up the client and the responses for connection management and message receipt.
var messagesReady = false; var mqttClient = null; function MQTTinitialize() { mqttClient = new Paho.MQTT.Client(MQTTHostname, Number(MQTTPort), "clientId"); mqttClient.onMessageArrived = onMessageArrived; // connect the client mqttClient.connect({ onSuccess: () => { messagesReady = true; } }); // set callback handlers mqttClient.onConnectionLost = (response) => { // messagesReady = false; // if (response.errorCode !== 0) { console.log("onConnectionLost:"+response.errorMessage); } setTimeout(() => { MQTTinitialize() },1000); // try again in a second }; }
Setting up Subscription
With the connection ready, the client can subscribe to message channels, send messages on them, etc. Just a few routines can do most of the work necessary to connect panels with the MQTT pathways.
For the panel SPWA, the moment of subscription can be used to establish the association between the panel and the topic, the MCU identifier.
function panelSubcription(topic,panel) { gTopicToPanel[topic] = panel; gPanelToTopic[panel] = topic; mqttClient.subscribe(topic); }
Given that an MCU is publishing on its topic, the SPWA will receive a message. Here, the Paho message is unpacked. And, then the message is passed on into the application mechanics.
function onMessageArrived(pmessage) { // var topic = pmessage.destinationName; var message = pmessage.payloadString; // var panel = gTopicToPanel[topic]; deliverToPanel(panel,message); }
So, now all we need to do is create deliverToPanel which should be somewhat like the interval handler that we had before. However, the panel is clearly identified, and only the keyed data sent in the particular message may be updated.
function deliverToPanel(panel,message) { var refall = panelApp.$refs; // all named children that panels var pdata = refall[panel][0]; // off Vue translation, but it’s there. var MCU_updates = JSON.parse(message); for ( var ky in MCU_updates ) { pdata[ky] = MCU_updates[ky] } }
This deliverToPanel function is abstract enough to allow any panel definition with any number of data points for animation.
Sending Messages
To complete the application loop between the MCU and the SPWA, we define a function to send a message.
function sendPanelMessage(panel,message) { var topic = gPanelToTopic[panel]; var pmessage = new Paho.MQTT.Message(message); pmessage.destinationName = topic; mqttClient.send(pmessage); }
The sendPanelMessage function does no more than sending the message out on the same topic pathway that the SPWA subscribes to.
As we plan to make the icon buttons responsible for bringing in some number of panels for a single cluster of MCU’s, there will be more than one panel to take care of. But, we keep in mind that each panel corresponds to a single MCU, so we have a one-one mapping, for which we may use two JavaScript maps for the map and the inverse.
So, when do we send messages? Usually, the panel application will send a message when it wants to change the state of the MCU.
Keeping The View (Vue) State In Sync With Devices
One of the great things about Vue is that it is very easy to keep the data model synchronized with the activity of the user, who may edit fields, click on buttons, use sliders, etc. One can be sure that button and field changes will be reflected immediately in the components’ data fields.
But, we want changes to fire off messages to the MCU as soon as the changes occur. So, we seek to make use of the interface events that Vue may govern. We seek to respond to such an event, but only after the Vue data model is ready with the current value.
I created another kind of panel, this one with a fairly artistic looking button (perhaps inspired by Jackson Pollock). And, I went about turning it into something whose click reports the state back to the panel that contains it. That was not so simple a process.
One thing that threw me off is that I had forgotten some of the oddities in managing SVG. I first tried to change the style string so that the display field of the CSS style would either be “None” or “something”. But, the browser never rewrote the styles string. But, as that was cumbersome, I tried changing the CSS class. That also had no effect. But, there the visibility attribute, which most of us recall from old HTML (version 1.0 perhaps), but that is very up to date in SVG. And, that works well. All, I had to do was to get the button click event to propagate.
Vue has designed properties to propagate in one direction, parent to child. So, to change data in the application, or in the panel, you have to send a change event to the parent. Then, you can change the data. The change of the data element controlling the button causes Vue to update the property affecting the visibility of the SVG element we have chosen to indicate state. Here is an example:
Tumblr media
Finally, a collection of different types of panels each with instances assigned to separate MCU’s. (Large preview)
Each instance of the squiggly button panel is independent. So, some are ON and some are OFF.
This snippet of SVG contains the odd-looking yellow indicator:
<path :visibility="stateView" style="opacity:0.98000004;fill:#faea4a;fill-opacity:1;stroke:#eecd5c;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="sunthing" d="m -36.544616,12.266886 c 19.953088,17.062165 5.07961,-19.8251069 5.317463,8.531597 0.237853,28.356704 13.440044,-8.847959 -3.230451,10.779678 -16.670496,19.627638 14.254699,-2.017715 -11.652451,3.586456 -25.90715,5.60417 10.847826,19.889979 -8.095928,-1.546575 -18.943754,-21.436555 -1.177383,14.210702 -4.176821,-12.416207 -2.999438,-26.6269084 -17.110198,8.030902 2.14399,-8.927709 19.254188,-16.9586105 -19.075538,-8.0837048 9.448721,-5.4384245 28.52426,2.6452804 -9.707612,-11.6309807 10.245477,5.4311845 z" transform="translate(78.340803,6.1372042)" />
The visibility is populated by stateView, a computed variable that maps the state boolean to a string for SVG.
Here is the panel component definition template:
<script type="text/x-template" id="mcu-control-panel-template"> <div> <control-switch :state="bstate" v-on:changed="saveChanges" ></control-switch> <gauge :level="fluidLevel" ></gauge> </div> </script>
And, this is the JavaScript definition of the Vue panel with its children as subcomponents:
var widgdef = { data: function () { var currentPanel = { // at the top level, values controlling children bstate : true, fluidLevel : Math.round(Math.random()*100) } // return currentPanel }, template: '#mcu-control-panel-template', methods: { saveChanges: function() { // in real life, there is more specificity this.bstate = !this.bstate relayToMCU(this.name,"button",this.bstate) // to be defined } }, components: { 'control-switch' : { // the odd looking button props: [’state'], template: '#control-switch-template', // for demo it is in the page. computed: { // you saw this in the SVG above. stateView : function() { return ( this.state ) ? "visible" : "hidden" } }, methods : { // the button handler is in the SVG template at the top. stateChange : function () { // can send this.$emit('changed'); // tell the parent. See on the template instance } } }, 'gauge' : { // some other nice bit of SVG props: ['level'], template: '#gauge-template' } } }
So, now the mechanism for a single button embedded in a panel has been laid out. And, there has to be a hook for telling the MCU that something has taken place. It must be called immediately after the data state of the panel component has been updated. Let’s define it here:
function relayToMCU(panel,switchName,bstate) { var message = switchName + ':' + bstate // a on element parameter string. sendPanelMessage(panel,message) }
There is the state change on it’s way to hardware in just two lines of code.
But, this is a fairly simple case. Any switch can be viewed as a function call to a piece of hardware out in the world. So, the string might contain the switch name and several other data elements. So, the component method that registers change will have to have some custom handling in it in order that it might gather together all the pieces of data set on the panel and send them along in one command string. Even the command string is a little simple. If the MCU is quite small, the command string might have to be translated into a code. If the MCU has a great deal of capability, the command string might actually be a JSON structure or perhaps all the data that the panel hosts.
In this discussion, the buttons on the icon panel contain the name of the panel to fetch. That may also be fairly simplified as well. It seems to make sense that that parameter can stand for any panel that might be stored in an enterprises databases. But, perhaps it is some formula. Perhaps, information about the panel should be wrapped around the panel definition that we receive from the server. In any case, the basics can be easily expanded upon once certain headaches are out of the way, like making the SVG respond to clicks properly.
Conclusion
This discussion has laid out some basic steps and decisions that lead to the realization of a Single Page Web App (SPWA) that can interface with IoT devices. We now know how to get panels from a web server and turn them into MCU interface.
There is much more to this discussion with quite a few other discussions that may follow. Starting with Vue is one thing to think about. But, then there is the whole MCU story, which we have only briefly touched upon.
In particular, by selecting MQTT as a communication substrate, we assume that IoT devices on the other end can somehow be ruled by MQTT. But, that may not always be the case. Sometimes gateways are needed if MQTT is to gain access to a device with serial links or Bluetooth. Or, perhaps all one ever needs from on the web page is WebSockets. Nevertheless, we used MQTT as an example to show how Vue could both receive and send data while keeping its data state in sync with devices.
Once again we only have part of the story. This time it is for synchronization because the page should be able to deal with alerts and bother the user if something critical is happening. Sometimes messages can get lost. So, we have to have a mechanism for acknowledgments.
Finally, it is my opinion that Vue makes updating data upon receipt quite elegant. But, sending the state changes is not so straight forward. It does not seem to make the job much simpler than can be done with vanilla JavaScript. But, there is a way and it makes sense.
Perhaps a clean library can be built to make a universal set of components for all panels. The elements for making such libraries and having them stored in a database have been briefly mentioned. Tools that go beyond just making SVG pictures may have to be developed. In any case, there are likely many things that can be done for the next steps.
Tumblr media
(dm, yk, il)
0 notes
siliconwebx · 7 years ago
Text
Using Event Bus to Share Props Between Vue Components
By default, communication between Vue components happen with the use of props. Props are properties that are passed from a parent component to a child component. For example, here’s a component where title is a prop:
<blog-post title="My journey with Vue"></blog-post>
Props are always passed from the parent component to the child component. As your application increases in complexity, you slowly hit what is called prop drilling here’s a relate article that is React-focused, but totally applies). Prop drilling is the idea of passing props down and down and down to child components — and, as you might imagine, it’s generally a tedious process.
So, tedious prop drilling can be one potential problem in a complex. The other has to do with the communication between unrelated components. We can tackle all of this by making use of an Event Bus.
What is an Event Bus? Well, it’s kind of summed up in the name itself. It’s a mode of transportation for one component to pass props from one component to another, no matter where those components are located in the tree.
Practice task: Building a counter
Let’s build something together to demonstrate the concept of an event bus. A counter that adds or subtracts a submitted value and tallies the overall total is a good place to start:
See the Pen Vuejs Event Bus Counter by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.
To make use of an event bus, we first need to initialize it like so:
import Vue from 'vue'; const eventBus = new Vue();
This sets an instance of Vue to eventBus. You can name it anything you’d like, whatsoever. If you are making use of a single-file component, then you should have snippet in a separate file, since you will have to export the Vue instance assigned to eventBus anyway:
import Vue from 'vue'; export const eventBus = new Vue();
With that done, we can start making use of it in our counter component.
Here’s what we want to do:
We want to have a count with an initial value of 0.
We want an input field that accepts numeric values.
We want two buttons: one that will add the submitted numeric value to the count when clicked and the other to subtract that submitted numeric value from the count when clicked.
We want a confirmation of what happened when the count changes.
This is how the template looks with each of those elements in place:
<div id="app"> <h2>Counter</h2> <h2></h2> <input type="number" v-model="entry" /> <div class="div__buttons"> <button class="incrementButton" @click.prevent="handleIncrement"> Increment </button> <button class="decrementButton" @click.prevent="handleDecrement"> Decrement </button> </div> <p></p> </div>
We bind the input field to a value called entry, which we’ll use to either increase or decrease the count, depending on what is entered by the user. When either button is clicked, we trigger a method that should either increase or decrease the value of count. Finally, that thing contained in <p> tag is the message we’ll print that summarizes the change to the count.
Here’s how that all comes together in our script:
new Vue({ el: '#app', data() { return { count: 0, text: '', entry: 0 } }, created() { eventBus.$on('count-incremented', () => { this.text = `Count was increased` setTimeout(() => { this.text = ''; }, 3000); }) eventBus.$on('count-decremented', () => { this.text = `Count was decreased` setTimeout(() => { this.text = ''; }, 3000); }) }, methods: { handleIncrement() { this.count += parseInt(this.entry, 10); eventBus.$emit('count-incremented') this.entry = 0; }, handleDecrement() { this.count -= parseInt(this.entry, 10); eventBus.$emit('count-decremented') this.entry = 0; } } })
You may have noticed that we’re about to hop on the event bus by looking at that code.
First thing we’ve got to do is establish a path for sending an event from one component to another. We can pave that path using eventBus.$emit() (with emit being a fancy word for sending out). That sending is included in two methods, handleIncrement and handleDecrement, which is listening for the input submissions. And, once they happen, our event bus races to any component requesting data and sends the props over.
Tumblr media
You may have noticed that we are listening for both events in the created() lifecycle hook using eventBus.$on(). In both events, we have to pass in the string that corresponds to the event we emitted. This is like an identifier for the particular event and the thing that established a way for a component to receive data. When eventBus recognizes a particular event that has been announced, the function that follows is called — and we set a text to display what had happened, and make it it disappear after three seconds.
Practice task: Handling multiple components
Let’s say we are working on a profile page where users can update their name and email address for an app and then see the update without refreshing the page. This can be achieved smoothly using event bus, even though we are dealing with two components this time: the user profile and the form that submits profile changes.
See the Pen Vuejs Event Bus 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.
Here is the template:
<div class="container"> <div id="profile"> <h2>Profile</h2> <div> <p>Name: </p> <p>Email: </p> </div> </div> <div id="edit__profile"> <h2>Enter your details below:</h2> <form @submit.prevent="handleSubmit"> <div class="form-field"> <label>Name:</label> <input type="text" v-model="user.name" /> </div> <div class="form-field"> <label>Email:</label> <input type="text" v-model="user.email" /> </div> <button>Submit</button> </form> </div> </div>
We will pass the ids (user.name and user.email)to the corresponding component. First, let’s set up the template for the Edit Profile (edit__profile) component, which holds the name and email data we want to pass to the Profile component we’ll set up next. Again, we’ve established an event bus to emit that data after it detects that a submission event has taken place.
new Vue({ el: "#edit__profile", data() { return { user: { name: '', email: '' } } }, methods: { handleSubmit() { eventHub.$emit('form-submitted', this.user) this.user = {} } } })
This data will be used to reactively update the profile on the user in the Profile (profile) component, which looking for name and email to come in when the bus arrives to its hub.
new Vue({ el: '#profile', data() { return { name: '', email: '' } }, created() { eventHub.$on('form-submitted', ({ name, email}) => { this.name = name; this.email = email }) } })
Their bags are packed. Now all they have to do is go home.
Pretty cool, right? Even though the Edit Profile and Profile components are unrelated — or not in a direct parent-child relationship) — it is possible for them to communicate with each other, linked by the same event.
Rollin’ right along
I have found Event Bus helpful in cases where I want to enable reactivity in my app — specifically, to update a component based on the response obtained from the server without causing the page to refresh. It is also possible that the event that gets emitted can be listened to by more than one component.
If you have other interesting scenarios of using event bus, I’ll love to hear about them in the comments. 🚌
The post Using Event Bus to Share Props Between Vue Components appeared first on CSS-Tricks.
😉SiliconWeb Dev. | 🌐CSS-Tricks
0 notes
programmingbiters-blog · 7 years ago
Photo
Tumblr media
New Post has been published on https://programmingbiters.com/codeigniter-restful-web-services-codexworld/
CodeIgniter RESTful Web Services - CodexWorld
youtube
Representational state transfer (REST) or RESTful web services provide a way to exchange data between applications or systems on the Internet. RESTful web service also refers as RESTful API, uses HTTP request to GET, PUT, POST and DELETE data across platforms. In present days, RESTful API is an essential component of the web application.
When the CodeIgniter application requires communicating with another application, RESTful API is needed to integrate into CodeIgniter. Using RESTful API in CodeIgniter, you can exchange data between different applications or platform. This tutorial shows RESTful server implementation for CodeIgniter and you will learn how to create RESTful web services in CodeIgniter.
If you are beginners to CodeIgniter, first see CodeIgniter from Scratch tutorial to setup and configure CodeIgniter application.
To demonstrate CodeIgniter REST API, we will implement CRUD operations in CodeIgniter web service. The following tasks will be performed to create a simple REST API in CodeIgniter.
Setup RESTful library for CodeIgniter.
Create API method to fetch the user information via GET request.
Create API methods to add, edit, and delete user information via POST, PUT, and DELETE request.
Interact with the CodeIgniter Rest API using PHP cURL.
Test HTTP calls with Google Chrome Postman extension.
Before you get started, take a look the files structure of CodeIgniter REST API.
Create Database Tables
To store user’s information, a table needs to be created in the database. The following SQL creates a users table with some basic fields in MySQL database.
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(100) COLLATE utf8_unicode_ci NOT NULL, `last_name` varchar(100) COLLATE utf8_unicode_ci NOT NULL, `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `phone` varchar(20) COLLATE utf8_unicode_ci NOT NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL, `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
The following SQL creates a keys table to store REST API key for authentication.
CREATE TABLE `keys` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `key` varchar(40) NOT NULL, `level` int(2) NOT NULL, `ignore_limits` tinyint(1) NOT NULL DEFAULT '0', `is_private_key` tinyint(1) NOT NULL DEFAULT '0', `ip_addresses` text, `date_created` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Now insert an API key in keys table, which will be used on API call.
INSERT INTO `keys` (`id`, `user_id`, `key`, `level`, `ignore_limits`, `is_private_key`, `ip_addresses`, `date_created`) VALUES (1, 0, 'CODEX@123', 0, 0, 0, NULL, '2017-10-12 13:34:33');
CodeIgniter REST Controller Setup
We will use CodeIgniter REST_Controller to build RESTful web services in CodeIgniter. Follow the below steps to setup REST Controller Library in your CodeIgniter application.
Download REST config file and place in the application/config/ directory. Open the application/config/rest.php file and setup the following configuration.
Download REST_Controller file and place in the application/libraries/ directory.
Download Format class file and place in the application/libraries/ directory.
Download Language file and place in the application/language/english/ directory.
Note that: All the required library files are included in our example CodeIgniter application, so, you don’t need to download these files separately. Download our source code to get sample CodeIgniter RESTful Web service application.
Create Model
Open the application/models/ directory and create User.php file and add the following code to handle the database related works. The User model has the following methods to fetch, insert, update, and delete user data in the database.
__construct() – Load the database library.
getRows() – Fetch the user data from the users table and returns single row or multiple rows.
insert() – Insert user data in the users table.
user_put() – Update user data in the users table based on the given ID.
user_delete() – Delete user from the users table based on the given ID.
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class 
User extends CI_Model 
    public function 
__construct()          parent::__construct();                  //load database library         $this->load->database();     
    /*      * Fetch user data      */     function getRows($id = "")         if(!empty($id))             $query = $this->db->get_where('users', array('id' => $id));             return $query->row_array();         else             $query = $this->db->get('users');             return $query->result_array();                        /*      * Insert user data      */     public function insert($data = array())          if(!array_key_exists('created', $data))             $data['created'] = date("Y-m-d H:i:s");                  if(!array_key_exists('modified', $data))             $data['modified'] = date("Y-m-d H:i:s");                  $insert = $this->db->insert('users', $data);         if($insert)             return $this->db->insert_id();         else             return false;                        /*      * Update user data      */     public function update($data, $id)          if(!empty($data) && !empty($id))             if(!array_key_exists('modified', $data))                 $data['modified'] = date("Y-m-d H:i:s");                          $update = $this->db->update('users', $data, array('id'=>$id));             return $update?true:false;         else             return false;                        /*      * Delete user data      */     public function delete($id)         $delete = $this->db->delete('users',array('id'=>$id));         return $delete?true:false;     
?>
Create API Controller
It’s always a good idea to group all API controllers in a separate folder for better usability. So, create an api/ folder in application/controllers/ directory to place the controller which will be used for API call. Open the application/controllers/api/ directory and create Example.php file. At first, include the REST Controller library and add the following code. The Example API controller has the following methods to handle the GET, POST, PUT, and DELETE request.
__construct() – Load the User model.
user_get() – Return the user data from database. If the ID parameter doesn’t exist, it returns all the rows otherwise single row will be returned.
user_post() – Add user data to the database.
user_put() – Update the user data in the database based on the ID.
user_delete() – Delete the user from the database based on the ID.
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');//include Rest Controller library require APPPATH . '/libraries/REST_Controller.php';
class 
Example extends REST_Controller 
    public function 
__construct()           parent::__construct();                  //load user model         $this->load->model('user');               public function user_get($id = 0)          //returns all rows if the id parameter doesn't exist,         //otherwise single row will be returned         $users = $this->user->getRows($id);                  //check if the user data exists         if(!empty($users))             //set the response and exit             $this->response($users, REST_Controller::HTTP_OK);         else             //set the response and exit             $this->response([                 'status' => FALSE,                 'message' => 'No user were found.'             ], REST_Controller::HTTP_NOT_FOUND);                        public function user_post()          $userData = array();         $userData['first_name'] = $this->post('first_name');         $userData['last_name'] = $this->post('last_name');         $userData['email'] = $this->post('email');         $userData['phone'] = $this->post('phone');         if(!empty($userData['first_name']) && !empty($userData['last_name']) && !empty($userData['email']) && !empty($userData['phone']))             //insert user data             $insert = $this->user->insert($userData);                          //check if the user data inserted             if($insert)                 //set the response and exit                 $this->response([                     'status' => TRUE,                     'message' => 'User has been added successfully.'                 ], REST_Controller::HTTP_OK);             else                 //set the response and exit                 $this->response("Some problems occurred, please try again.", REST_Controller::HTTP_BAD_REQUEST);                      else             //set the response and exit             $this->response("Provide complete user information to create.", REST_Controller::HTTP_BAD_REQUEST);                        public function user_put()          $userData = array();         $id = $this->put('id');         $userData['first_name'] = $this->put('first_name');         $userData['last_name'] = $this->put('last_name');         $userData['email'] = $this->put('email');         $userData['phone'] = $this->put('phone');         if(!empty($id) && !empty($userData['first_name']) && !empty($userData['last_name']) && !empty($userData['email']) && !empty($userData['phone']))             //update user data             $update = $this->user->update($userData, $id);                          //check if the user data updated             if($update)                 //set the response and exit                 $this->response([                     'status' => TRUE,                     'message' => 'User has been updated successfully.'                 ], REST_Controller::HTTP_OK);             else                 //set the response and exit                 $this->response("Some problems occurred, please try again.", REST_Controller::HTTP_BAD_REQUEST);                      else             //set the response and exit             $this->response("Provide complete user information to update.", REST_Controller::HTTP_BAD_REQUEST);                        public function user_delete($id)         //check whether post id is not empty         if($id)             //delete post             $delete = $this->user->delete($id);                          if($delete)                 //set the response and exit                 $this->response([                     'status' => TRUE,                     'message' => 'User has been removed successfully.'                 ], REST_Controller::HTTP_OK);             else                 //set the response and exit                 $this->response("Some problems occurred, please try again.", REST_Controller::HTTP_BAD_REQUEST);                      else             //set the response and exit             $this->response([                 'status' => FALSE,                 'message' => 'No user were found.'             ], REST_Controller::HTTP_NOT_FOUND);                 ?>
Interacting with CodeIgniter RESTful Web Services
Now it’s time to interact with the CodeIgniter RESTful Web Services. The cURL is the most flexible and easiest way to interact with a REST API. In the following example code, we will show you how to send GET, POST, PUT and DELETE request to CodeIgniter REST API using PHP cURL. Also, HTTP Basic authentication and API key will be used to connect with RESTful API.
Retrieve User Data via REST API The following code performs a GET request to fetch the user data via RESTful Web Services (Example API).
//API URL $url = 'http://localhost/codeigniter/api/example/user/';//API key $apiKey = 'CODEX@123';//Auth credentials $username = "admin"; $password = "1234";//create a new cURL resource $ch = curl_init($url);curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-API-KEY: " . $apiKey)); curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");$result = curl_exec($ch);//close cURL resource curl_close($ch);
Insert User Data via REST API The following code performs a POST request to insert user data via RESTful Web Services (Example API).
//API URL $url = 'http://localhost/codeigniter/api/example/user/';//API key $apiKey = 'CODEX@123';//Auth credentials $username = "admin"; $password = "1234";//user information $userData = array(     'first_name' => 'John',     'last_name' => 'Doe',     'email' => '[email protected]',     'phone' => '123-456-7890' );//create a new cURL resource $ch = curl_init($url);curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-API-KEY: " . $apiKey)); curl_setopt($ch, CURLOPT_USERPWD, "$username:$password"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $userData);$result = curl_exec($ch);//close cURL resource curl_close($ch);
Update User Data via REST API The following code performs a PUT request to update user data via RESTful Web Services (Example API).
//API URL $url = 'http://localhost/codeigniter/api/example/user/';//API key $apiKey = 'CODEX@123';//Auth credentials $username = "admin"; $password = "1234";//user information $userData = array(     'id' => 2,     'first_name' => 'John2',     'last_name' => 'Doe2',     'email' => '[email protected]',     'phone' => '098-765-4321' );//create a new cURL resource $ch = curl_init($url);curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-API-KEY: '.$apiKey, 'Content-Type: application/x-www-form-urlencoded')); curl_setopt($ch, CURLOPT_USERPWD, "$username:$password"); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($userData));$result = curl_exec($ch);//close cURL resource curl_close($ch);
Delete User Data via REST API The following code performs a DELETE request to delete user data via RESTful Web Services (Example API).
//API URL $url = 'http://localhost/codeigniter/api/example/user/2';//API key $apiKey = 'CODEX@123';//Auth credentials $username = "admin"; $password = "1234";//create a new cURL resource $ch = curl_init($url);curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-API-KEY: " . $apiKey)); curl_setopt($ch, CURLOPT_USERPWD, "$username:$password"); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');$result = curl_exec($ch);//close cURL resource curl_close($ch);
Test HTTP calls with Postman Extension
Postman Extension makes API development faster, easier, and better. Install Postman Extension for testing the API call.
Are you want to get implementation help, or modify or extend the functionality of this script? Submit paid service request
0 notes