Angular 2 Component Not Displaying in index.html - angular2-components

Im very new to Angular 2 so bear with me.
Im trying to get a new component to appear in the index.html page.
The file set is from the basic quick start files from GitHub.
I created a new component as such:
import { Component } from '#angular/core';
#Component({
selector: 'app-user-item',
template: `<h1>It works!</h1>`,
})
export class UserItemComponent {
}
I have declared the selector tags in HTML as such:
<!DOCTYPE html>
<html>
<head>
<title>Angular QuickStart</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading AppComponent content here ...</my-app>
<app-user-item>loading another component</app-user-item>
</body>
</html>
I even tried adding the import to the top of app.module.ts and component name to the declarations array in app.module.ts. But still nothing.
I checked my file structure and there is a js version of user-item.component.ts. But I cannot see changes.
Any help would be appreciated.
Cheers

I had this exact same problem. In your app.module.ts file make sure to include your component in your bootstrap declaration.
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { UserItemComponent } from './UserItem.component';
#NgModule({
declarations : [
AppComponent,
UserItemComponent
],
imports: [
BrowserModule
],
bootstrap: [
AppComponent,
UserItemComponent
],
providers: [],
})
export class AppModule { }

user-item.component.ts:
import { Component } from '#angular/core';
#Component ({
selector: 'app-user-item',
template: `<p>child item</p>`
)}
export class UserItemComponent {
constructor(){ }
}
user.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'app-user',
template: ` <h2> My User Item </h2>
<app-user-item></app-user-item>`
})
export class UserComponent {
constructor() {}
}
user.module.ts:
import { NgModule } from '#angular/core';
import { UserComponent } from './user-component';
import { UserItemComponent } from './user-item-component';
#NgModule({
declarations: [
UserComponent,
UserItemComponent
]
})
export class UserModule {}
I really encourage you to use angular-cli (https://github.com/angular/angular-cli). And to do the tutorials on angular page.
However, For your use case the code above should be sufficient and work.
Usually you declare your subcomponent in the same module as the parentcomponent.
This module is imported by the app.module (root module)
Look at the Master-Detail Component Tutorials of Angular
https://angular.io/docs/ts/latest/tutorial/toh-pt2.html

In my case Selector defined in app.component.ts file was not matching with index.html

Related

Spartacus metatag overwritten by config even if no url is set

I have a setup with Spartacus v2 (Hybris 2005) in a CCv2 enviroment.
I'm currently facing the issue that the content of the metatag <meta name="occ-backend-base-url" content="OCC_BACKEND_BASE_URL_VALUE" /> isn't replaced in any of my enviroments.
This happens because I need to set occ prefix in my app.module.ts to with hybris 2005:
backend: {
occ: {
prefix: '/occ/v2/'
}
}
Is there a frontend only solution for this issue or do we need to change the prefix back to /rest/v2 in the backend?
Is there a reason that the meta tag is ignored even if no url is defined in the backend.occ data object, but only the prefix?
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Spartacusstore</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">
<meta name="occ-backend-base-url" content="OCC_BACKEND_BASE_URL_VALUE" />
</head>
<body>
<app-root></app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</html>
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { translations, translationChunksConfig } from '#spartacus/assets';
import { B2cStorefrontModule } from '#spartacus/storefront';
import { OccConfig, I18nModule, TranslatePipe } from '#spartacus/core';
const occConfig: OccConfig = { backend: { occ: {} } };
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
B2cStorefrontModule.withConfig({
backend: {
occ: {
prefix: '/occ/v2/'
}
},
checkout: {
guest: true
},
context: {
currency: ['USD'],
language: ['en'],
baseSite: ['electronics-spa']
},
i18n: {
resources: translations,
chunks: translationChunksConfig,
fallbackLang: 'en'
},
features: {
level: '2.0'
},
}),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

How to add element-ui (now called element-plus) to Vue3 project?

I have been using "element-ui" and now moving forward to new version of Vue3.
Seems they published a new version called "element-plus" but the tutorial is not updated.
import Vue from 'vue'; // not working in Vue3
import ElementUI from 'element-plus';
import 'element-ui/lib/theme-chalk/index.css';
...
Vue.use(ElementUI); // no "Vue" in Vue3 anymore
...
createApp(App).mount('#app') // the new project creation
https://element-plus.org/#/en-US/component/quickstart
Anyone manged to do it right and it works?
If you are using vue 3 you need to import createApp as well as css from 'element-plus/...' folder. Then you instance your app using the vue function imported, basically you pass your main app component to the function as an argument:
import { createApp } from 'vue'
import App from './YourMainApp.vue'
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
let app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
You can also do it very easy without any js bundler.
Here is a sample:
var Main = {
data() {
return {
message: 'Hello World!'
}
},
methods: {
click() {
console.log('click()');
}
}
};
const app = Vue.createApp(Main);
app.use(ElementPlus);
app.mount("#app")
<html>
<head>
<link rel="stylesheet" href="//unpkg.com/element-plus/theme-chalk/index.css">
</head>
<body>
<script src="//unpkg.com/vue#next"></script>
<script src="//unpkg.com/element-plus/dist/index.full.js"></script>
<div id="app">
<el-button type="primary" size="medium" #click="click">{{message}}</el-button>
</div>
</body>
</html>

Import object js in vue and exclude this file from bundling

I start with the simple vue.js application. I have icons in base64 format and put all them as object in separately file icons.js. I want to import this object to the file globals.js as globals constant and use this constant in all places where I need icons. BUT, this file does not need to be bundled.
I have files icons.js, globals.js, main.js, App.vue.
icons.js:
export const iconsData =
{
"large": {
"2": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAA3CAYAAAD6+O8NAAAAGXRFWHRTb2Z0d2FyZQB",
"3": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwE",
"777": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAAAUCAYAAAAJD/ojAAAAGXRFWHRTb2Z0d2FyZQB"
},
"small": {
"2": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAAARCAYAAABjEtTjAAAAGXRFWHRTb2Z0d2F",
"3": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADkAAAAqCAYAAAAJWvOwAAAAGXRFWHRTb2Z0d2Fy",
"777": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAqCAYAAADMKGkhAAAAGXRFWHRTb2Z0d2",
}
};
globals.js:
import { iconsData } from './assets/icons'
export const icons = {
getIcon: function (iconNumber) {
if (!iconsData.large[iconNumber]) {
return "";
} else {
return iconsData.large[iconNumber];
}
},
isIcon:function (iconNumber) {
return iconsData.large[iconNumber];
}
};
In my App.vue :
<template>
<div id="app">
<div v-for="channel in channels">
<div class="icon" >
<img v-if="icons.isIcon(channel.number)" :src="icons.getIcon(channel.number)" >
<div v-if="!icons.isIcon(channel.number)" class="channel-name">{{channel.name}}</div>
</div>
</div>
</div>
</template>
<script>
import {icons} from "./globals"
export default {
name: 'app',
components: {
},
data() {
return {
icons: icons,
}
},
}
</script>
I tried
1) Vue.js exclude settings file from being bundled - not work for me
2)Exclude json file from being bundled in Vue from official documentation my file is in assets, but if I put absolutely path in global.js
import { iconsData } from '/assets/icons' - application not compiled.
Maybe this not right - import icons as const global? What I can do to leave file icons.js separately?
I suppose you're using webpack to build as you've tagged the question with VueCLI. If you don't want the icon data to be bundled, then you need to include such hints to webpack that the icon data should reside in a separate chunk than your app bundle. Something like this should work:
const iconsData = import('./assets/icons').then(icons => icons.iconsData);
You can also customize what the chunk should be named. Let's say you want it to be named icons-data, then you can do this:
const iconsData = import(/* webpackChunkName: "icons-data" */ './assets/icons').then(icons => icons.iconsData);
solved the problem this way:
1) Delete from icons.js word export
const iconsData =
{
"large": {
"2": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAA3CAYAAAD6+O8NAAAAGXRFWHRTb2Z0d2FyZQB",
"3": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwE",
"777": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAAAUCAYAAAAJD/ojAAAAGXRFWHRTb2Z0d2FyZQB"
},
"small": {
"2": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAAARCAYAAABjEtTjAAAAGXRFWHRTb2Z0d2F",
"3": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADkAAAAqCAYAAAAJWvOwAAAAGXRFWHRTb2Z0d2Fy",
"777": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAqCAYAAADMKGkhAAAAGXRFWHRTb2Z0d2",
}
};
2) Delete from globals.js import
export const icons = {
getIcon: function (iconNumber) {
if (!iconsData.large[iconNumber]) {
return "";
} else {
return iconsData.large[iconNumber];
}
},
isIcon:function (iconNumber) {
return iconsData.large[iconNumber];
}
};
3) Add to index.html referense to icons.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>Icons</title>
<script type="text/javascript" src="<%= BASE_URL %>icons.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but egg doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
4) Copy file icons.js to the public folder and to the src root
How I understand - this way exclude the file from webpack in "old school" way. How to do this with webpack - I do not understand.

Vuejs single file components mixed with normal components

I am trying to mix vuejs single file components with the normal style of components (not sure what they are called) which I have existing code developed for already.
main.js
import Vue from 'vue'
import test from './test.vue'
import VueMaterial from 'vue-material'
Vue.use(VueMaterial)
new Vue({
el: '#app',
render: h => h(test,
{props: {
testprop: 'ttttt'
}
}),
data:{
// /testprop: 'tytytytyty'
}
})
test.vue
<template>
<div>
<my-component></my-component>
<div>This is the first single page component</div>
</div>
</template>
<script>
import MyComponent from '../src/components/MyComponent.js'
import TestTest from '../src/components/TestTest.vue'
export default {
name: 'MainApp',
props: ['testprop'],
components: {
TestTest,
MyComponent
},
mounted: function(){
},
computed:{
returnProp: function(){
return this.testprop
}
}
}
</script>
<style lang="scss" scoped>
.md-menu {
margin: 24px;
}
</style>
MyComponent.js Normal style component
window.Vue = require('Vue') //would give errors vue undefined if i dont't add this line
Vue.component('my-component', {
name: 'my-component',
template: '<div>Normal component</div>'
})
index.html
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1,minimal-ui" name="viewport">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons">
<link rel="stylesheet" href="https://unpkg.com/vue-material#beta/dist/vue-material.min.css">
<link rel="stylesheet" href="https://unpkg.com/vue-material#beta/dist/theme/default.css">
<title>vuematerial</title>
</head>
<body>
<div id="app">
<main-app :testprop="testprop"></main-app>
</div>
<script src="dist/build.js"></script>
</body>
</html>
The single file component and a child single file component (not showed here) display fine. The normal type will show up as
<!--function (t,n,r,i){return Mt(e,t,n,r,i,!0)}-->
In the generated html.
Iv'e also tried doing the MyComponent import in the main.js file.
Any ideas?
I don't really want to convert all my existing components into single file ones :(
According to the docs, a child component is an object, not something attached to the Vue instance (i.e Vue.component()) so declare your component like this:
MyComponent.js
export default {
name: 'my-component',
template: '<div>Normal component</div>'
}
If you want to keep the format of MyComponent as is then you'll need to register the component before the new Vue call.

Angular2 Testing http service saying map function not supported

I trying to create a test against a simple service, but I am getting an error that says "TypeError: Object doesn't support property or method 'map'" When I run this service for real (not as a test) it works fine and I don't have any issues. This is the first time I'm trying to get a test setup for Angular2, so I could be missing something. Here are my components.
recentActivity.service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import * as toPromise from 'rxjs/add/operator/toPromise';
import * as map from 'rxjs/add/operator/map';
import { RecentActivity } from './recentActivity.model';
#Injectable()
export class RecentActivityService {
private baseUrl = '/RecentActivity/';
constructor(private http: Http) {
}
get(): Observable<any> {
//return undefined;
return this.http
.get(this.baseUrl + 'Get')
.map((response: Response) => response.json())
//.toPromise()
;
}
}
recentActivity.spec.ts
import { async, describe, it, expect, inject, beforeEach, beforeEachProviders } from '#angular/core/testing';
import { Http, BaseRequestOptions, Response, ResponseOptions } from '#angular/http';
import { MockBackend, MockConnection } from '#angular/http/testing';
import { RecentActivity } from './recentActivity.model';
import { RecentActivityService } from './recentActivity.service';
describe('Recent Activity Service', () => {
let service: RecentActivityService;
let mockBackend: MockBackend;
const mockResponseData: RecentActivity[] = [
{ Name: 'Test Result 1', Url: '#/TestResult1' },
{ Name: 'Test Result 2', Url: '#/TestResult2' },
{ Name: 'Test Result 3', Url: '#/TestResult3' }
];
beforeEachProviders(() => [
RecentActivityService,
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend, options) => new Http(backend, options),
deps: [MockBackend, BaseRequestOptions]
}
]);
beforeEach(inject([RecentActivityService, MockBackend], (ras, mb) => {
service = ras;
mockBackend = mb;
}));
it('Can load list of recent activities', (done) => {
mockBackend.connections.subscribe((connection: MockConnection) => {
const responseOpts = new ResponseOptions({ body: JSON.stringify(mockResponseData) });
connection.mockRespond(new Response(responseOpts));
});
service.get()
.subscribe((results: RecentActivity[]) => {
expect(results.length).toEqual(3);
expect(results[0].Name).toEqual('Test Result 1');
expect(results[1].Name).toEqual('Test Result 2');
expect(results[2].Name).toEqual('Test Result 3');
done();
});
});
});
unit-tests.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Unit Tests</title>
<link rel="stylesheet" href="./libs/jasmine-core/lib/jasmine-core/jasmine.css">
<script src="./libs/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="./libs/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="./libs/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="./libs/core-js/client/shim.min.js"></script>
<script src="./libs/zone.js/dist/zone.js"></script>
<script src="./libs/reflect-metadata/Reflect.js"></script>
<script src="./libs/systemjs/dist/system.src.js"></script>
<script src="./libs/rxjs/bundles/Rx.js"></script>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/underscore/underscore.js"></script>
<script src="~/lib/moment/moment.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="./systemjs.config.js"></script>
<script>
// #2. Configure systemjs to use the .js extension
// for imports from the app folder
System.config({
packages: {
'app': { defaultExtension: 'js' }
}
});
// #3. Import the spec file explicitly
Promise.all([
System.import('app/recentActivity/recentActivity.spec'),
System.import('app/pipes/styleVisibility.spec')
])
// #4. wait for all imports to load ...
// then re-execute `window.onload` which
// triggers the Jasmine test-runner start
// or explain what went wrong.
.then(window.onload)
.catch(console.error.bind(console));
</script>
</head>
<body>
</body>
</html>
I've tried to piece together the pieces to get this to work, but I can't figure out what I'm missing. Also as a side note I'm using Visual Studio 2015 and that is also giving a warning saying "Property map does not exist on type 'Observable'".
Like I mentioned everything works when I run this service for real and it returns my information from my backend no problem.
All I had to do was change the imports in the recentActivity.service.ts file to be
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
I still get an error (red squiggly) In Visual Studio, so if somebody could tell me how to get rid of that I would appreciate it.
The above solution works for me too. But since I was also using .do and .catch, I had to import those as well:
import 'rxjs/add/operator.do;
import 'rxjs/add/operator.catch;
Hope this helps others also.