1671551605
Ember and Vue are the two fastest-growing JavaScript frameworks right now. With Ember releasing its version 3.7 this year and Vue’s version 3 slated to come out later in the year, the popularity of both frameworks has been increasing rapidly.
Medium highlights how this popularity is because maintaining JavaScript is challenging and time-consuming. Updating a single line of code can result in around 11 updates on the UI. JavaScript is one of the most in-demand forms of programming with Yoss reporting that 72% of tech workers use the coding language. With many coders using it, there is a huge demand for programs that can simplify the language. This wide user base is the reason why JavaScript frameworks like Ember and Vue are the most employed tools by coders. It significantly reduces the amount of code that needs to be written, which in turn reduces the chance of mistakes that would cause the UI to be out of sync with the data.
Frameworks allow coders to build components that combine to form a web app. Because these components are responsible for the data they require, this cuts down coding time as not everything has to be defined.
Vue and Ember are two of the easiest frameworks to learn and use. With well-structured guides and great API documentation, the two are thriving despite having no single company backing them up. Other competitor frameworks are owned and updated by giant companies, which is why they have a much higher user base and are seen as more sustainable. React was developed by Facebook, while Angular was developed by Google and uses Microsoft’s TypeScript.
If you want to streamline your coding efficiency, which should you use? Vue or Ember?
Developed by Evan You and released in 2014, Vue is an open-source front-end JavaScript framework designed to possess both the advantages of React and Angular. Similar to React, it renders components to a virtual DOM, and like Angular, binds data with the components and relies on the existing components already found in the DOM.
With a smaller ecosystem and faster rendering, Vue is preferred by most compared to Ember. One of its best uses is when you want to update an older web application to a modern engine for the simplest integration process. Its simple code structure also allows for users to discover errors much quicker, as well as providing more flexibility for developers.
The dependence on the core framework remains the biggest source of skepticism for its user base. While most Vue users are in China, the most used PHP framework Laravel encourages its users to develop with Vue.
Ember is a very huge and versatile front-end framework created by Yehuda Katz, a core member of popular JavaScript library JQuery. While Ember doesn’t have a single company backer, corporations like Yahoo, LinkedIn, and Bustle are some of its biggest users.
Ember calls itself ‘the framework for the ambitious coders,’ as it targets startups that need the vast range of options that it offers. As a DZone infographic comparing JavaScript frameworks points out, Ember self-configures many aspects if you don’t define them yourself. With fast loading speeds and simpler codes, Ember is popular with newly designed web applications that need very complex components.
Ember offers high productivity and scalability with its numerous added layers. While it’s the most organised framework out there, it also means it has less flexibility, in addition to sometimes breaking CSS+ styles already rendered into the code.
By most benchmarks, Vue is a clear winner from a technical standpoint. While Vue suffers from a lack of institutional support, many developers prefer its utility and high productivity. And with the release of Vue 3.0, Packt reveals that it will have a cleaner and a more maintainable source code.
On the other hand, with the scalability it affords, there are plenty of practical use cases where Ember comes out better. Ember, for one, continues to enjoy a huge package ecosystem that delivers more powerful add-ons. With the developers’ promised release of Ember Octane this year, it will be faster and smaller.
If you found this tutorial helpful then don't forget to share.
Original article source at: https://makitweb.com/
1667476380
Bad software is everywhere, and we're tired of it. Sentry is on a mission to help developers write better software faster, so we can get back to enjoying technology. If you want to join us Check out our open positions
This is the next line of Sentry JavaScript SDKs, comprised in the @sentry/
namespace. It will provide a more convenient interface and improved consistency between various JavaScript environments.
Sentry is Hiring!!!
Would you like to work on Open Source software and help maintain this repository? Apply today: https://boards.greenhouse.io/sentry.
For each major JavaScript platform, there is a specific high-level SDK that provides all the tools you need in a single package. Please refer to the README and instructions of those SDKs for more detailed information:
@sentry/browser
: SDK for Browsers@sentry/node
: SDK for Node including integrations for Express@sentry/angular
: Browser SDK with Angular integration enabled@sentry/ember
: Browser SDK with Ember integration enabled@sentry/react
: Browser SDK with React integration enabled@sentry/svelte
: Browser SDK with Svelte integration enabled@sentry/vue
: Browser SDK with Vue integration enabled@sentry/gatsby
: SDK for Gatsby@sentry/nextjs
: SDK for Next.js@sentry/remix
: SDK for Remix@sentry/integrations
: Pluggable integrations that can be used to enhance JS SDKs@sentry/serverless
: SDK for Serverless Platforms (AWS, GCP)@sentry/electron
: SDK for Electron with support for native crashes@sentry/react-native
: SDK for React Native with support for native crashes@sentry/capacitor
: SDK for Capacitor Apps and Ionic with support for native crashesTo install a SDK, simply add the high-level package, for example:
npm install --save @sentry/browser
yarn add @sentry/browser
Setup and usage of these SDKs always follows the same principle.
import { init, captureMessage } from '@sentry/browser';
init({
dsn: '__DSN__',
// ...
});
captureMessage('Hello, world!');
Besides the high-level SDKs, this repository contains shared packages, helpers and configuration used for SDK development. If you're thinking about contributing to or creating a JavaScript-based SDK, have a look at the resources below:
@sentry/tracing
: Provides Integrations and extensions for Performance Monitoring / Tracing@sentry/core
: The base for all JavaScript SDKs with interfaces, type definitions and base classes.@sentry/utils
: A set of helpers and utility functions useful for various SDKs.@sentry/types
: Types used in all packages.Author: Getsentry
Source Code: https://github.com/getsentry/sentry-javascript
License: MIT license
1658554140
An Ember addon to turn Ember apps into cross-platform desktop applications, taking care of development, tests, compilation, and installer creation.
Ember-Electron is a small open source project. Use GitHub Issues to report bugs and errors within the addon.
If you need help using the addon with your application, may we recommend the excellent Ember community? You can check out the various places to get help here. In particular, the Ember community Discord has a #topic-desktop
channel which is a great place to ask questions about ember-electron
. If you have questions regarding Electron, their Slack and forum will be helpful as well.
Ember-Electron builds on prior work done by @brzpegasus (author of ember-cli-nwjs
) and @joostdevries (author of ember-cli-remote-inspector
). Our gratitude to both of them for their amazing work.
Author: Adopted-ember-addons
Source Code: https://github.com/adopted-ember-addons/ember-electron
License: View license
1656371640
Ember Charts
A charting library built with the Ember.js and d3.js frameworks. It includes time series, bar, pie, and scatter charts which are easy to extend and modify. The out-of-the-box behavior these chart components represents our thoughts on best practices in chart interactivity and presentation.
https://emberjs.jsbin.com/rekawobugu/1/edit
Unfortunately, this version of Ember Charts is out of date, and the current maintainers of Ember Charts at Addepar have not been able to update it recently.
Ember Charts is an Ember CLI addon published to the public NPM repository at https://www.npmjs.com/package/ember-charts , so it can be installed like so:
# ember-cli >= 0.2.0
ember install:addon ember-charts
# ember-cli >= 0.2.3
ember install ember-charts
Once it's installed, you can customize the look of Ember Charts with CSS.
npm install -g bower # install Bower
bower install ember-charts --save
Using Ember Charts with bower is deprecated and will eventually be removed. We recommend that you migrate your apps to Ember CLI! Documentation has been updated to show Ember CLI usage. If you need documentation for globals-based use, please check out version 0.5.0 of Ember Charts and follow the setup instructions under "Running Old Versions" to display the old guides.
After cloning this repo, install dependencies and run the demo application:
yarn
bower install
ember serve
Now you can:
We aim to support the last two major versions of every common browser.
If you need to support further browsers, we welcome pull requests with fixes.
Touch support may work but has not been tested.
Got something to add? Great! Bug reports, feature ideas, and (especially) pull requests are extremely helpful, and this project wouldn't be where it is today without lots of help from the community.
Please read the contribution guidelines for directions on opening issues and working on the project.
Ember Charts uses Semantic Versioning to keep track of releases using the following format:
<major>.<minor>.<patch>
In a nutshell, this means:
Prior to releasing, ensure that the CHANGELOG.md is updated to track any changes that have been made since the prior release.
We increment version numbers and release using release-it:
npm run release -- <options>
The local configuration file for release-it
is named .release-it.json
, found in the root directory of the repository.
By default, release-it
without options will increment the version number (X.Y.Z
--> X.Y.(Z+1)
) in the VERSION
file and package.json
file, and then commit the resulting changes to the ember-charts git repository.
If you want to control the version number, use these options:
npm run release -- major # 1.2.3 -> 2.0.0
npm run release -- minor # 1.2.3 -> 1.3.0
npm run release -- X.Y.Z # 1.2.3 -> X.Y.Z
Ember Charts has also configured release-it
to automatically update the gh-pages
branch (from which the demo and documentation website is published). This is done by pushing the /ember-dist/
directory after constructing it with ember build
. These commands can be seen in the .release-it.json
file.
release-it
is also configured to automatically publish the updated version to npm
.
Lastly, the new version should be released on Github, which can be done via the Github UI after the steps above are complete.
https://opensource.addepar.com/ember-charts/
Author: Addepar
Source Code: https://github.com/Addepar/ember-charts/
License: View license
1653063780
ember-template-lint
ember-template-lint
is a library that will lint your handlebars template and return error results.
For example, if the rule no-bare-strings
is enabled, this template would be in violation:
{{! app/components/my-thing/template.hbs }}
<div>A bare string</div>
When the ember-template-lint
executable is run, we would have a single result indicating that the no-bare-strings
rule found an error.
^12.22.0 || ^14.17.0 || >=16.0.0
npm install --save-dev ember-template-lint
yarn add --dev ember-template-lint
Note: this library is installed by default with new Ember apps.
While ember-template-lint
does have a Node API, the main way to use it is through its executable, which is intended to be installed locally within a project.
Basic usage is as straightforward as
ember-template-lint .
See documentation on workflow examples.
See documentation on the todo functionality.
You can turn on specific rules by toggling them in a .template-lintrc.js
file at the base of your project, or at a custom relative path which may be identified using the CLI:
module.exports = {
extends: 'recommended',
rules: {
'no-bare-strings': true,
},
};
For more detailed information see configuration.
Name | Description | |
---|---|---|
✅ | recommended | Enables the recommended rules. |
💅 | stylistic | Enables stylistic rules for those who aren't ready to adopt ember-template-lint-plugin-prettier (including stylistic rules that were previously in the recommended preset in ember-template-lint v1). |
⌨️ | a11y | Enables A11Y rules. Its goal is to include all A11Y related rules, therefore it does not follow the same SemVer policy as the other presets. Please see versioning for more details. |
Each rule has emojis denoting:
--fix
command line option--fix
optionYou can add a fixer to a rule. See fixer documentation for more details.
It is possible to share a config (extends
) or plugin (custom rules) across projects. See ember-template-lint-plugin-peopleconnect for an example.
You can define and use your own custom rules using the plugin system. See plugin documentation for more details.
The semver policy for this addon can be read here: semver policy.
See the Contributing Guidelines for information on how to help out.
Author: ember-template-lint
Source Code: https://github.com/ember-template-lint/ember-template-lint
License: MIT license
1652483760
Text Mask is an input mask library. It can create input masks for phone, date, currency, zip code, percentage, email, and literally anything!
There are convenient wrappers for React, Angular 2, Ember, and Vue.
See it in action, check out the demo page.
IE9+, Android, Samsung Internet, Windows Phone, iOS, Opera, Firefox, Safari, and Chrome
Text Mask is very configurable and allows you to create any type of input mask with minimal APIs. See the documentation for details.
You can easily expand the base functionality of Text Mask with addons for more mask types. Checkout existing addons.
Text Mask supports pasting, browser auto-fill, and all operations that a user would expect while interacting with an input field.
It works on mobile, has no 3rd party dependencies, and has a tiny footprint (less than 4KB gzipped).
⚠️ This library is not maintained. Pull-requests and issues are not monitored. Alternatives to text-mask
include:
If you know other alternatives that should be listed here, email me at msafi@msafi.com.
Author: Text-mask
Source Code: https://github.com/text-mask/text-mask
License: Unlicense license
1650961964
Today the Ember project is releasing version 4.3 of Ember.js, Ember Data, and Ember CLI.
This release kicks off the 4.4 beta cycle for all sub-projects. We encourage our community (especially addon authors) to help test these beta builds and report any bugs before they are published as a final release in six weeks' time. The ember-try addon is a great way to continuously test your projects against the latest Ember releases.
You can read more about our general release process here:
Ember.js is the core framework for building ambitious web applications.
Ember.js 4.3 is an incremental, backwards compatible release of Ember with bug fixes, performance improvements, and minor deprecations.
Ember.js 4.3 introduced 3 bug fixes.
RouterService#transitionTo
no longer adds unspecified default query parameters to the URL (#19971).FactoryManager
correctly associate props with factory and owner (#20024).Ember.js 4.3 introduced 0 features.
Ember.js 4.3 introduced 0 deprecations.
For more details on changes in Ember.js 4.3, please review the Ember.js 4.3.0 release page.
Ember Data is the official data persistence library for Ember.js applications.
Ember Data 4.3 introduced many bug fixes! Contributors to the project were hard at work to address things that were reported between v3.28
and v4.2
.
Many of the bugfixes listed below have been backported to v3.28
. That means if you get the latest patch release of v3.28-v4.2
, you will get these benefits too.
The list below covers highlights only. See the commit history for a comprehensive list.
createRecord
crashed when a setter which sets an attribute is involved in the createRecord
.await
for loading relationships #7684.Ember Data 4.3 introduced 4 features.
DEBUG
mode, it is now easier to dig into Store
, Symbol
, and RecordReference
.attributesDefinitionFor
and relationshipsDefinitionFor
have a simpler API, following RFC 794.Ember Data 4.3 introduced 0 deprecations.
Support for the toJSON
method on Ember Data records has been removed. It was deprecated in 3.x
and slated for removal in 4.x
. If your app uses this method, follow the deprecation guide.
Some more previously-deprecated APIs were slated for removal in the 4.x
series, and have now been removed:
didCreate
.belongs-to-push
of record.mismatched-inverse
.For more details on changes in Ember Data 4.3, please review the Ember Data 4.3.0 commits.
Ember CLI is the command line interface for managing and packaging Ember.js applications.
You may upgrade Ember CLI using the ember-cli-update
project:
npx ember-cli-update
This utility will help you to update your app or addon to the latest Ember CLI version. You will probably encounter merge conflicts, in which the default behavior is to let you resolve conflicts on your own. For more information on the ember-cli-update
project, see the GitHub README.
While it is recommended to keep Ember CLI versions in sync with Ember and Ember Data, this is not required. After updating ember-cli, you can keep your current version(s) of Ember or Ember Data by editing package.json
to revert the changes to the lines containing ember-source
and ember-data
.
Ember CLI 4.3 introduced 1 bug fix.
gitignore
file (#9680).Ember CLI 4.3 introduced 2 features.
tests/helpers/index.js
file where setupApplicationTest
, setupRenderingTest
, and setupTest
functions will be wrapped and exported, creating a single place to edit for each type of test setup. Tests generated using ember generate
will import the setup functions from that file.ember generate
command (#9387). This allows you to run ember g ../../../node_modules/ember-source/blueprints/component
to generate a component.Ember CLI 4.3 introduced 1 deprecation.
For more details on the changes in Ember CLI 4.3 and detailed upgrade instructions, please review the Ember CLI 4.3.0 release page.
As a community-driven open-source project with an ambitious scope, each of these releases serves as a reminder that the Ember project would not have been possible without your continued support. We are extremely grateful to our contributors for their efforts.
Original article source at https://blog.emberjs.com
#ember #programming
1649429720
Ember Generators (ember-tools)
This generator set is used in ember-tools to create the application objects.
npm install loom-generators-ember --save
The --save
is important, loom needs to read your package.json to find the generators.
generate component x-buttonset
generate controller users/mini-profile
generate controller application type:array
generate helper capitalize
generate mixin queryable
generate route index
generate template profile
generate view index
That's pretty much everything.
Models were removed, I (or you) will be creating a different generator set for ember-data models, serializers and adapters later.
I welcome pull requests :)
npm install
npm test
Author: Ryanflorence
Source Code: https://github.com/ryanflorence/loom-generators-ember
License: MIT License
1649160600
Love open source? We're hiring Node.js engineers to work on Ghost full-time.
The easiest way to get a production instance deployed is with our official Ghost(Pro) managed service. It takes about 2 minutes to launch a new site with worldwide CDN, backups, security and maintenance all done for you.
For most people this ends up being the best value option cause of how much time it saves — and 100% of revenue goes to the Ghost Foundation; funding the maintenance and further development of the project itself. So you’ll be supporting open source software and getting a great service!
If you prefer to run on your own infrastructure, we also offer official 1-off installs and managed support and maintenance plans via Ghost(Valet) - which can save a substantial amount of developer time and resources.
If you want to run your own instance of Ghost, in most cases the best way is to use our CLI tool
npm install ghost-cli -g
Then, if installing locally add the local
flag to get up and running in under a minute - Local install docs
ghost install local
or on a server run the full install, including automatic SSL setup using LetsEncrypt - Production install docs
ghost install
Check out our official documentation for more information about our recommended hosting stack & properly upgrading Ghost, plus everything you need to develop your own Ghost themes or work with our API.
For anyone wishing to contribute to Ghost or to hack/customize core files we recommend following our full development setup guides: Contributor guide • Developer setup • Admin Client dev guide
We'd like to extend big thanks to our sponsors and partners who make Ghost possible. If you're interested in sponsoring Ghost and supporting the project, please check out our profile on GitHub sponsors :heart:
You can find answers to a huge variety of questions, along with a large community of helpful developers over on the Ghost forum - replies are generally very quick. Ghost(Pro) customers also have access to 24/7 email support.
To stay up to date with all the latest news and product updates, make sure you subscribe to our blog — or you can always follow us on Twitter, if you prefer your updates bite-sized and facetious. 🎷🐢
Author: TryGhost
Source Code: https://github.com/TryGhost/Ghost
License: MIT License
1648890002
Build bulletproof UI components faster
Storybook is a development environment for UI components. It allows you to browse a component library, view the different states of each component, and interactively develop and test components. Find out more at https://storybook.js.org.
Visit Storybook's website to learn more about Storybook, and to get started.
Documentation can be found Storybook's docs site.
Here are some featured examples that you can reference to see how Storybook works: https://storybook.js.org/docs/react/get-started/examples
Storybook comes with a lot of addons for component design, documentation, testing, interactivity, and so on. Storybook's API makes it possible to configure and extend in various ways. It has even been extended to support React Native, Android, iOS, and Flutter development for mobile.
For additional help, join us in the Storybook Discord.
Addons | |
---|---|
a11y | Test components for user accessibility in Storybook |
actions | Log actions as users interact with components in the Storybook UI |
backgrounds | Let users choose backgrounds in the Storybook UI |
cssresources | Dynamically add/remove css resources to the component iframe |
design assets | View images, videos, weblinks alongside your story |
docs | Add high quality documentation to your components |
events | Interactively fire events to components that respond to EventEmitter |
google-analytics | Reports google analytics on stories |
graphql | Query a GraphQL server within Storybook stories |
jest | View the results of components' unit tests in Storybook |
links | Create links between stories |
query params | Mock query params |
storyshots | Snapshot testing for components in Storybook |
storysource | View the code of your stories within the Storybook UI |
viewport | Change display sizes and layouts for responsive components using Storybook |
See Addon / Framework Support Table
Addons | |
---|---|
info | Annotate stories with extra component usage information |
notes | Annotate Storybook stories with notes |
contexts | Addon for driving your components under dynamic contexts |
options | Customize the Storybook UI in code |
knobs | Interactively edit component prop data in the Storybook UI |
In order to continue improving your experience, we have to eventually deprecate certain addons in favor of new, better tools.
If you're using info/notes, we highly recommend you to migrate to docs instead, and here is a guide to help you.
If you're using contexts, we highly recommend you to migrate to toolbars and here is a guide to help you.
We have a badge! Link it to your live Storybook example.
[](link to site)
If you're looking for material to use in your presentation about storybook, like logo's video material and the colors we use etc, you can find all of that at our brand repo.
We welcome contributions to Storybook!
Looking for a first issue to tackle?
Storybook is organized as a monorepo using Lerna. Useful scripts include:
yarn bootstrap
Installs package dependencies and links packages together - using lerna
yarn lint
boolean check if code conforms to linting rules - uses remark & eslint
yarn lint:js
- will check jsyarn lint:md
- will check markdown + code samplesyarn lint:js --fix
- will automatically fix jsyarn test
boolean check if unit tests all pass - uses jest
yarn run test --core --watch
- will run core tests in watch-modeDownload Details:
Author: storybookjs
Source Code: https://github.com/storybookjs/storybook
License: MIT
#storybook #react #javascript #testing #ember #html #angular #typescript #ui #reactnative #webpack #vue #webcomponent #svelte
1648093999
Ember Data is a powerful data layer, but it has its limitations and pain points, especially as applications grow in scale. Ember M3 builds on Ember Data's core, but replaces the default model class with an alternative that is more flexible and lightweight. In this talk, we'll explore M3's capabilities, and then test them out by building an app with M3 and Firestore, a realtime NoSQL database-as-a-service. As we'll see, M3 and Firestore make a perfect pair, enabling rapid prototyping and flexibility, while setting you up for success as your application grows.
#firebase #ember #database #nosql #firestore
1646815680
Love open source? We're hiring Node.js Engineers to work on Ghost full-time
The easiest way to get a production instance deployed is with our official Ghost(Pro) managed service. It takes about 2 minutes to launch a new site with worldwide CDN, backups, security and maintenance all done for you.
For most people this ends up being the best value option cause of how much time it saves — and 100% of revenue goes to the Ghost Foundation; funding the maintenance and further development of the project itself. So you’ll be supporting open source software and getting a great service!
If you prefer to run on your own infrastructure, we also offer official 1-off installs and managed support and maintenance plans via Ghost(Valet) - which can save a substantial amount of developer time and resources.
Quickstart Install
If you want to run your own instance of Ghost, in most cases the best way is to use our CLI tool
npm install ghost-cli -g
Then, if installing locally add the local
flag to get up and running in under a minute - Local install docs
ghost install local
or on a server run the full install, including automatic SSL setup using LetsEncrypt - Production install docs
ghost install
Check out our official documentation for more information about our recommended hosting stack & properly upgrading Ghost, plus everything you need to develop your own Ghost themes or work with our API.
For anyone wishing to contribute to Ghost or to hack/customize core files we recommend following our full development setup guides: Contributor Guide | Developer Setup | Admin Client Dev Guide
Ghost Sponsors
We'd like to extend big thanks to our sponsors and partners who make Ghost possible. If you're interested in sponsoring Ghost and supporting the project, please check out our profile on GitHub Sponsors :heart:
Getting Help
You can find answers to a huge variety of questions, along with a large community of helpful developers over on the Ghost forum - replies are generally very quick. Ghost(Pro) customers also have access to 24/7 email support.
To stay up to date with all the latest news and product updates, make sure you subscribe to our blog — or you can always follow us on Twitter, if you prefer your updates bite-sized and facetious. 🎷🐢
Author: TryGhost
Source Code: https://github.com/TryGhost/Ghost
License: MIT License
1642659000
Love open source? We're hiring Node.js Engineers to work on Ghost full-time
The easiest way to get a production instance deployed is with our official Ghost(Pro) managed service. It takes about 2 minutes to launch a new site with worldwide CDN, backups, security and maintenance all done for you.
For most people this ends up being the best value option cause of how much time it saves — and 100% of revenue goes to the Ghost Foundation; funding the maintenance and further development of the project itself. So you’ll be supporting open source software and getting a great service!
If you prefer to run on your own infrastructure, we also offer official 1-off installs and managed support and maintenance plans via Ghost(Valet) - which can save a substantial amount of developer time and resources.
Quickstart Install
If you want to run your own instance of Ghost, in most cases the best way is to use our CLI tool
npm install ghost-cli -g
Then, if installing locally add the local
flag to get up and running in under a minute - Local install docs
ghost install local
or on a server run the full install, including automatic SSL setup using LetsEncrypt - Production install docs
ghost install
Check out our official documentation for more information about our recommended hosting stack & properly upgrading Ghost, plus everything you need to develop your own Ghost themes or work with our API.
For anyone wishing to contribute to Ghost or to hack/customize core files we recommend following our full development setup guides: Contributor Guide | Developer Setup | Admin Client Dev Guide
Ghost Sponsors
We'd like to extend big thanks to our sponsors and partners who make Ghost possible. If you're interested in sponsoring Ghost and supporting the project, please check out our profile on GitHub Sponsors :heart:
Getting Help
You can find answers to a huge variety of questions, along with a large community of helpful developers over on the Ghost forum - replies are generally very quick. Ghost(Pro) customers also have access to 24/7 email support.
To stay up to date with all the latest news and product updates, make sure you subscribe to our blog — or you can always follow us on Twitter, if you prefer your updates bite-sized and facetious. :saxophone::turtle:
Author: Tryghost
Source Code: https://github.com/tryghost/Ghost
License: MIT License
1642588620
Ember.js is a JavaScript framework that greatly reduces the time, effort and resources needed to build any web application. It is focused on making you, the developer, as productive as possible by doing all the common, repetitive, yet essential, tasks involved in most web development projects.
With Ember, you get all of these things:
Find out more:
See CONTRIBUTING.md
Cross-browser testing provided by Browserstack.
Author: Emberjs
Source Code: https://github.com/emberjs/ember.js
License: MIT License
1638602047
Simple, flexible infinite scrolling for Ember CLI Apps. Works out of the box with the Kaminari Gem.
Also:
ember install ember-infinity
As of v2.0.0
, we support Node 10 and above. We test against ember-source > 3.8
. Try out v2.0.0
. If it doesn't work or you don't have the right polyfills because you are on an older Ember version, then v1.4.9
will be your best bet.
ember-infinity
exposes 3 consumable items for your application.
infinity service
infinity-loader component
Route Mixin (deprecated and removed as of 1.1). If you still want to upgrade, but keep your Route mixins, install 1.0.2
. See old docs (here)[https://github.com/ember-infinity/ember-infinity/blob/2e0cb02e5845a97cad8783893cd7f4ddcf5dc5a7/README.md]
Ember Infinity is based on a component-service approach wherein your application is viewed as an interaction between your components (ephemeral state) and service (long term state).
As a result, we can intelligently store your model state to provide you the ability to cache and invalidate your cache when you need to. If you provide an optional infinityCache
timestamp (in ms), the infinity service model
hook will return the existing collection (and not make a network request) if the timestamp has not yet expired. Be careful as this will also circumvent your ability to receive fresh data on every route visit.
Moreover, you are not restricted to only fetching items in the route. Fetch away in any top-level component!
Let's see how simple it is to fetch a list of products. Instead of this.store.query('product')
or this.store.findAll('product')
, you simply invoke this.infinity.model('product')
and under the hood, ember-infinity
will query the store and manage fetching new records for you!
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class InfinityRoute extends Route {
@service infinity
model() {
return this.infinity.model('product');
}
}
{{#each model as |product|}}
<h1>{{product.name}}</h1>
<h2>{{product.description}}</h2>
{{/each}}
<InfinityLoader @infinityModel={{model}} />
Whenever the infinity-loader
component is in view, we will fetch the next page for you.
By default, ember-infinity
expects the server response to contain something about how many total pages it can expect to fetch. ember-infinity
defaults to looking for something like meta: { total_pages: 20 }
in your response. See Advanced Usage.
Let's look at a more complicated example using multiple infinity models in a route. Super easy!
import Route from '@ember/routing/route';
import RSVP from 'rsvp';
import { inject as service } from '@ember/service';
export default class InfinityRoute extends Route {
@service infinity;
model() {
return RSVP.hash({
products: this.infinity.model('product'),
users: this.infinity.model('user')
});
}
}
{{!-- templates/products.hbs --}}
<aside>
{{#each model.users as |user|}}
<h1>{{user.username}}</h1>
{{/each}}
<InfinityLoader @infinityModel={{model.users}} />
</aside>
<section>
{{#each model.products as |product|}}
<h1>{{product.name}}</h1>
<h2>{{product.description}}</h2>
{{/each}}
<InfinityLoader @infinityModel={{model.products}} />
<section>
The infinity service also exposes 5 methods to fetch & mutate your collection:
The model
hook will fetch the first page you request and pass the result to your template.
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ProductsRoute extends Route {
@service infinity;
model() {
return this.infinity.model('product');
}
}
Moreover, if you want to intelligently cache your infinity model, pass { infinityCache: timestamp }
and we will return the cached collection if the future timestamp is less than the current time (in ms) if your users revisit the same route.
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ProductsRoute extends Route {
@service infinity;
model() {
return this.infinity.model('product', { infinityCache: 36000 }); // timestamp expiry of 10 minutes (in ms)
}
}
Let's see an example of using replace
.
import Controller from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class Products extends Route {
@service infinity;
actions: {
/**
@method filterProducts
@param {String} query
*/
async filterProducts(query) {
let products = await this.store.query('product', { query });
// model is the collection returned from the route model hook
this.infinity.replace(get(this, 'model'), products);
}
}
}
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ProductsRoute extends Route {
@service infinity
model() {
return this.infinity.model('product');
}
}
<input type="search" placeholder="Search Products" oninput={{action "filterProducts"}} />
{{#each model as |product|}}
<h1>{{product.name}}</h1>
<h2>{{product.description}}</h2>
{{/each}}
<InfinityLoader @infinityModel={{model.products}} />
If you want to use closure actions with ember-infinity
and the infinity-loader
component, you need to be a little bit more explicit. Generally you should let the infinity service handle fetching records for you, but if you have a special case, this is how you would do it:
See the Ember docs on passing actions to components here.
import Controller from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
export default class ProductsController extends Controller {
@service infinity
/**
Note this must be handled by you. An action will be called with the result of your Route model hook from the `infinity-loader` component, similar to this:
// closure action in infinity-loader component
get(this, 'infinityLoad')(infinityModelContent);
@method loadMoreProduct
@param {InfinityModel} products
*/
@action
loadMoreProduct(products) {
// Perform other logic ....
this.infinity.infinityLoad(products);
}
}
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ProductsRoute extends Route {
@service infinity
model() {
return this.infinity.model('product');
}
}
{{!-- some nested component in your template file where action bubbling does not reach your route --}}
{{#each model as |product|}}
<h1>{{product.name}}</h1>
<h2>{{product.description}}</h2>
{{/each}}
{{infinity-loader infinityModel=model infinityLoad=(action "loadMoreProduct")}}
In the world of optimistic route transitions & skeleton UI, it's necessary to return a POJO or similar primitive to Ember's Route#model hook to ensure the transition is not blocked by promise.
model() {
return {
posts: this.infinity.model('post')
};
}
By default, ember-infinity
will send pagination parameters as part of a GET request as follows
/items?per_page=5&page=1
and will expect to receive metadata in the response payload via a total_pages
param in a meta
object
{
items: [
{id: 1, name: 'Test'},
{id: 2, name: 'Test 2'}
],
meta: {
total_pages: 3
}
}
If you wish to customize some aspects of the JSON contract for pagination, you may do so via your model hook. For example, you may want to customize the following:
Default:
per_page
,page
,meta.total_pages
,meta.count
,Example Customization shown below:
per
,pg
,meta.total
,meta.records
,import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ProductsRoute extends Route {
@service infinity
model() {
/* Load pages of the Product Model, starting from page 1, in groups of 12. Also set query params by handing off to infinityModel */
return this.infinity.model('product', { perPage: 12, startingPage: 1,
perPageParam: 'per', pageParam: 'pg', totalPagesParam: 'meta.total', countParam: 'meta.records' });
}
}
This will result in request query params being sent out as follows
/items?per=5&pg=1
and ember-infinity
will be set up to parse the total number of pages from a JSON response like this:
{
items: [
...
],
meta: {
total: 3
}
}
You can also prevent the per_page
or page
parameters from being sent by setting perPageParam
or pageParam
to null
, respectively. Moreover, if your backend passes the total number of records instead of total pages, then as it's replacement, set the countParam
.
Lastly, if you need some global configuration for these params, setup an extended infinity model to import in each of your routes.
import Route from '@ember/routing/route';
import { inject } from '@ember/service';
export default class ProductsRoute extends Route {
@service infinity
model() {
return this.infinity.model('product', {
perPage: 20,
startingPage: 1,
perPageParam: 'page[size]',
pageParam: 'page[number]'
});
},
}
If you are serving a continuously updating stream, it's helpful to keep track of your place in the list while paginating to avoid duplicates. This is known as cursor-based pagination and is common in popular APIs like Twitter, Facebook, and Instagram. Instead of relying on page_number
to paginate, you'll want to extract the min_id
or min_updated_at
from each page of results, so that you can fetch the next page without risking duplicates if new items are added to the top of the list by other users in between requests.
To do this, implement the afterInfinityModel
hook as follows:
import Route from '@ember/routing/route';
import InfinityModel from 'ember-infinity/lib/infinity-model';
const ExtendedInfinityModel = InfinityModel.extend({
buildParams() {
let params = this._super(...arguments);
params['min_id']: get(this, '_minId'); // where `this` is the infinityModel instance
params['min_updated_at']: get(this, '_minUpdatedAt');
return params;
},
afterInfinityModel(posts) {
let loadedAny = posts.get('length') > 0;
this.set('canLoadMore', loadedAny);
this.set('_minId', posts.get('lastObject.id'));
this.set('_minUpdatedAt', posts.get('lastObject.updated_at').toISOString());
}
});
export default class PostsRoute extends Route {
@service infinity
model() {
return this.infinity.model('post', {}, ExtendedInfinityModel);
}
}
You can also provide additional static parameters to infinityModel
that will be passed to your backend server in addition to the pagination params. For instance, in the following example a category
parameter is added:
return this.infinity.model('product', { perPage: 12, startingPage: 1,
category: 'furniture' });
As of 1.0+, you can override or extend the behavior of Ember Infinity by providing a class that extends InfinityModel as a third argument to the Route#infinityModel hook.
import InfinityModel from 'ember-infinity/lib/infinity-model';
const ExtendedInfinityModel = InfinityModel.extend({
buildParams() {
let params = this._super(...arguments);
params['category_id'] = get(this, 'global.categoryId');
return params;
}
});
export default class ProductsRoute extends Route {
@service infinity
@service global
@computed('global.categoryId')
get categoryId() {
return get(this, 'global.categoryId');
}
model() {
const { global } = this;
this.infinity.model('product', {}, ExtendedInfinityModel.extend({ global }));
}
}
There is a lot you can do with this! Here is a simple use case where, say you have an API that does not return total_pages
or count
and you also don't need a loading spinner. Just set canLoadMore
to true and ember-infinity
will always try to fetch new records when the infinity-loader
comes into viewport.
import InfinityModel from 'ember-infinity/lib/infinity-model';
class ExtendedInfinityModel extends InfinityModel {
canLoadMore = true;
}
export default class ProductsRoute extends Route {
@service infinity
model() {
this.infinity.model('product', {}, ExtendedInfinityModel.extend());
}
}
isLoaded
says if the model is loaded after fetching results
loadingMore
says if the model is currently loading more items
isError
says if the fetch failed
The infinity model also provides following hooks:
afterInfinityModel
In some cases, a single call to your data store isn't enough. The afterInfinityModel
method is available for those cases when you need to chain together functions or promises after fetching a model.
As a simple example, let's say you had a blog and just needed to set a property on each Post model after fetching all of them:
ember-infinity
Service approachimport Route from '@ember/routing/route';
import InfinityModel from 'ember-infinity/lib/infinity-model';
const ExtendedInfinityModel = InfinityModel.extend({
afterInfinityModel(posts) {
this.setEach('author', 'Jane Smith');
}
});
export default class PostsRoute extends Route {
@service infinity
model() {
return this.infinity.model('post', {}, ExtendedInfinityModel);
}
}
As a more complex example, let's say you had a blog with Posts and Authors as separate related models and you needed to extract an association from Posts. In that case, return the collection you want from afterInfinityModel:
import Route from '@ember/routing/route';
import InfinityModel from 'ember-infinity/lib/infinity-model';
const ExtendedInfinityModel = InfinityModel.extend({
afterInfinityModel(posts) {
return posts.mapBy('author').uniq();
}
});
export default class PostsRoute extends Route {
@service infinity
model() {
return this.infinity.model('post', {}, ExtendedInfinityModel);
}
}
afterInfinityModel
should return either a promise, ArrayProxy, or a falsy value. The returned value, when not falsy, will take the place of the resolved promise object and, if it is a promise, will hold execution until resolved. In the case of a falsy value, the original promise result is used.
So relating this to the examples above... In the first example, afterInfinityModel
does not have an explicit return defined so the original posts promise result is used. In the second example, the returned collection of authors is used.
infinityModelUpdated
Triggered on the route whenever new objects are pushed into the infinityModel.
Args:
lastPageLoaded
totalPages
infinityModel
infinityModelLoaded
Triggered on InfinityModel when is fully loaded.
Args:
import Route from '@ember/routing/route';
import InfinityModel from 'ember-infinity/lib/infinity-model';
const ExtendedInfinityModel = InfinityModel.extend({
infinityModelUpdated({ lastPageLoaded, totalPages, newObjects }) {
Ember.Logger.debug('updated with more items');
},
infinityModelLoaded({ totalPages }) {
Ember.Logger.info('no more items to load');
}
});
export default class ProductsRoute extends Route {
@service infinity
model() {
return this.infinity.model('product', { perPage: 12, startingPage: 1 }, ExtendedInfinityModel);
}
}
Chances are you'll want to scroll some source other than the default ember-data store to infinity. You can do that by injecting your store into the route and specifying the store to the infinityModel options:
import { inject as service } from '@ember/service';
export default class ProductsRoute extends Route {
@service infinity
@service('my-custom-store') customStore
model(params) {
return this.infinity.model('product', {
perPage: 12,
startingPage: 1,
store: this.customStore, // custom ember-data store or ember-redux / ember-cli-simple-store / your own hand rolled store (see dummy app)
storeFindMethod: 'findAll' // should return a promise (optional if custom store method uses `query`)
})
}
}
The infinity-loader
component as some extra options to make working with it easy! It is based on the IntersectionObserver API. In essence, instead of basing your scrolling on Events (synchronous), it instead behaves asynchronously, thus not blocking the main thread.
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
Closure actions are enabled in the 1.0.0
series.
<InfinityLoader
@infinityModel={{model}}
@infinityLoad={{action "loadMoreProducts"}} />
<InfinityLoader
@infinityModel={{model}}
@hideOnInfinity={{true}} />
Now, when the Infinity Model is fully loaded, the infinity-loader
will hide itself and set isDoneLoading
to true
.
Versions less than 1.0.0 called this property destroyOnInfinity
<InfinityLoader
@infinityModel={{model}}
@infinityLoad={{action "loadMoreProducts"}}
@developmentMode={{true}} />
This simply stops the infinity-loader
from fetching triggering loads, so that you can work on its appearance.
<InfinityLoader
@infinityModel={{model}}
@infinityLoad={{action "loadMoreProducts"}}
loadingText="Loading..."
loadedText="Loaded!" />
By default, the infinity-loader
will just output a span
showing its status.
{{#infinity-loader infinityModel=model infinityLoad=(action "infinityLoad")}}
<img src="loading-spinner.gif" />
{{/infinity-loader}}
If you provide a block to the component, it will render the block instead of rendering loadingText
or loadedText
. This will allow you to provide your own custom markup or styling for the loading state.
.infinity-loader {
background-color: wheat;
&.reached-infinity {
background-color: lavender;
}
}
When the Infinity Model loads entirely, the reached-infinity
class is added to the component.
ember generate infinity-template
Will install the default infinity-loader
template into your host app, at app/templates/components/infinity-loader
.
<InfinityLoader @scrollable="#content" />
You can optionally pass in a CSS style selector string. If not present, scrollable will default to using the window. This is useful for scrollable areas that are constrained in the window.
<InfinityLoader @loadPrevious={{true}} />
<ul>...</ul>
<InfinityLoader />
To load elements above your list on load, place an infinity-loader component above the list with `loadPrevious=true`.
<InfinityLoader @triggerOffset={{offset}} />
You can optionally pass an offset value. This value will be used when calculating if the bottom of the scrollable has been reached.
<InfinityLoader @eventDebounce={{50}} />
Default is 50ms. You can optionally pass a debounce time to delay loading the list when reach bottom of list
ember-infinity
with buttonYou can use the service loading magic of ember-infinity without using the InfinityLoader component.
load-more-button.js:
export default class InfinityComponent extends Component {
@service infinity
loadText = 'Load more';
loadedText = 'Loaded';
onClick() {
this.infinity.infinityLoad(this.infinityModel);
}
}
load-more-button.hbs:
{{#if @infinityModel.reachedInfinity}}
<button>{{loadedText}}</button>
{{else}}
<button>{{loadText}}</button>
{{/if}}
template.hbs:
<ul class="test-list">
{{#each @model as |item|}}
<li>{{item.name}}</li>
{{/each}}
</ul>
<LoadMoreButton @infinityModel={{model}} />
template.hbs:
{{#if hasClickedLoadMore}}
{{infinity-loader infinityModel=model triggerOffset=400}}
{{else}}
<button {{action (toggle 'hasClickedLoadMore' this)}}>Load more</button>
{{/if}}
The basic idea here is to:
If your route loads on page 3, it will fetch page 2 on load. As the user scrolls up, it will fetch page 1 and stop loading from there. If you are already on page 1, no actions will be fired to fetch the previous page.
<ul>
<InfinityLoader
@infinityModel={{model}}
@loadPrevious={{true}}
@loadedText={{null}}
@loadingText={{null}} />
{{#each @model as |item|}}
<li>{{item.id}}. {{item.name}}</li>
{{/each}}
<InfinityLoader
@infinityModel={{model}}
@loadingText="Loading more awesome records..."
@loadedText="Loaded all the records!"
@triggerOffset={{500}} />
</ul>
Coming
Testing can be a breeze once you have an example. So here is an example! Note this is using Ember's new testing APIs.
import { find, findAll, visit, waitFor, waitUntil } from '@ember/test-helpers';
test('fetches more data when scrolled into viewport', async function(assert) {
await visit('/infinity-scrollable');
assert.equal(findAll('.t-items').length, 10);
assert.equal(findAll('.infinity-scrollable.inactive').length, 1, 'component is inactive before fetching more data');
document.querySelector('.infinity-scrollable').scrollIntoView();
await waitFor('.infinity-scrollable.inactive');
assert.equal(findAll('.t-items').length, 20);
assert.equal(findAll('.infinity-scrollable.inactive').length, 1, 'component is inactive after fetching more data');
});
test('fetch more data using waitUntil', async function(assert) {
await visit('/infinity-scrollable');
assert.equal(findAll('.t-items').length, 10);
assert.equal(findAll('.infinity-scrollable.inactive').length, 1, 'component is inactive before fetching more data');
document.querySelector('.infinity-scrollable').scrollIntoView();
await waitUntil(() => {
return findAll('.t-items').length === 20;
});
assert.equal(findAll('.t-items').length, 20);
assert.equal(findAll('.infinity-scrollable.inactive').length, 1, 'component is inactive after fetching more data');
});
Download Details:
Author: ember-infinity
The Demo/Documentation: View The Demo/Documentation
Official Website: https://github.com/ember-infinity/ember-infinity
License: MIT
#ember