Angular 2.x change <title> in head (outside my app) - javascript

I think it should be easy but I cannot find how.
I have something like
<html>
<head>
<title>{{'a' + 'b'}}</title>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
It seems like I cannot access anything outside my-app.
In angular 1.x it was easy, I was able to add ng-app on any element (<html ng-app="myApp">).
Now I think I'm able only bootstrap in body.
I know I can manually bootstrap somehow (didn't try yet), but dynamically change title in single page applications should be super-easy, shouldn't it?

Angular2 can't be bootstrapped to entire html. But you can use Title Service.
A service that can be used to get and set the title of a current HTML document.
It has 2 methods:
getTitle()
setTitle()
Don't forget to check the dependency injection section out to see how you can use the services.
EDIT:
As of the release (2.0.0), this is how you can do it:
import { Title } from '#angular/platform-browser';
export class SomeComponent {
constructor(title: Title) {
// title.getTitle();
// title.setTitle('new title');
}
}
And the docs for the Title service are now here: https://angular.io/docs/ts/latest/api/platform-browser/index/Title-class.html

Related

Exclude Vue Component from stylesheet of existing application

We build a Vue component(using vuetify) into an existing .net MVC application.
The application loads the webpack into a div.
The problem is that the vue component inherits all the CSS of the existing application.
A simplified HTML version looks like this:
<html>
<head>
</head>
<body>
...
<div class="VUE_CLASS">
//vue component...
</div>
...
</body>
</html>
The Style is written in css.less.
I tried to exclude the VUE_CLASS from all CSS Rules of the existing application by applying a :not(.VUE_CLASS) and a div:not(.VUE_CLASS). I also tried to wrap it around all rules in the css.less:
*:not(.VUE_CLASS){
//...css rules of the existing application
}
It doesn't work
I read about some other strategies (https://kloudless.com/blog/2019/02/05/creating-a-reusable-vuetify-component-to-use-in-other-apps/). Using an iframe is not an option because we can't access our backed from an iframe. I can't use Web components as well, because we have to support ie11.
Is it possible to exclude the div and all its child elements using less?
Thank you & Best regards,
Finn
What if you just reset all CSS styles for VUE_CLASS selector?
Try adding this rule at the end of the <style> tag:
.VUE_CLASS {
all: unset !important;
/* Write the other styles for this component below */
}

How to querySelector an element in an html import from a document that imports it?

Let say I have a html document with this div inside :
div.html
<div class="thediv">
<h1>test</h1>
<p class="insert"></p>
</div>
from index.html, I import it
<link rel="import" href="/path/to/div.html">
Now If I type in the console or in a script
const div = document.querySelector('.thediv');
div is null, as if the div just vanished. But I am sure there is a way to select the element because some webcomponents libraries allow programmer to define their own custom elements one by file.
I tried many things but can't find the solution.
Thanks for the help.
update :
This is true for any HTML Elements (not just div). I just pick an example for the question.
You can reference the document set at <link> element with rel attribute set to "import" using .import property of <link> element, see also Is there a way to know if a link/script is still pending or has it failed, How to append a whole html file with jquery
document.querySelector("link[rel=import][href='template1.html']")
.import.querySelector("#template1")
Solution found here: https://www.html5rocks.com/en/tutorials/webcomponents/imports/
import.html
<template>
<h1>Hello World!</h1>
<!-- Img is not requested until the <template> goes live. -->
<img src="world.png">
<script>alert("Executed when the template is activated.");</script>
</template>
index.html
<head>
<link rel="import" href="import.html">
</head>
<body>
<div id="container"></div>
<script>
var link = document.querySelector('link[rel="import"]');
// Clone the <template> in the import.
var template = link.import.querySelector('template');
var clone = document.importNode(template.content, true);
document.querySelector('#container').appendChild(clone);
</script>
</body>
I had 2 nice answers on my question and they helped me to find a more suitable solution for my specific problem I'm sharing here.
Again what I tried to achieve was to querySelector an element defined in an html import from the main document (i.e. index.html).
If we write something like
<div id="thediv">
...
</div>
at the root of an html import, the element won't be included in the body of the main document (I think each document has its own namespace or something like that).
#guest271314 recommended to use the import property of a link element to access the content of the fetched resource but see my comment on the same post. I think this is not really neat when you deal with documents that imports other documents that imports others...
#MaxBilbow recommended the same method providing a link and an example chunk using template. Again this is not really nice when you deal with relational imports. But the link gave me the solution.
In my imported document, I write an additional script :
div.html
<div id="thediv">
...
</div>
<script>
document.body.prepend(
document.currentScript.ownerDocument.querySelector('#thediv'));
</script>
Now when the html import is fetched the script will get executed and prepend the html chunk into the body of the main document.
index.html
<link rel="import" href="div.html">
<script>
// now I can querySelector('#thediv')
</script>
This is just an example and it is a dummy one, but I think I will mostly use that technique for templates, templates are hidden and it's ok to prepend them to the main document.
If you think that method could have flaws, please comment.
HTML Imports is deprecated and has now been removed as of M80. See https://www.chromestatus.com/features/5144752345317376 and https://developers.google.com/web/updates/2019/07/web-components-time-to-upgrade for more details.
You ca use fetch() to import your web component
How to separate web components to individual files and load them?

Gist-embed with Angular app

Trying to get gist-embed (https://github.com/blairvanderhoof/gist-embed) working within my Angular app but with no luck.
It works no problem on my homepage (which is not part of the Angular app) but when I use something like:
<code data-gist-id="<gist-id>"></code>
within the app it won't show. There are no messages in the console to explain why though.
Could someone explain why and offer a solution?
(function($) {
$(function() {
// find all elements containing "data-gist-id" attribute.
$('[data-gist-id]').each(function() {
var $elem = $(this),
id,
that lib is coded in such a way one cant really use it in angular,you'll have to look for a fork that offers a proper jquery plugin architecture you can use into a directive.That lib doesnt respect basic jQuery plugin architecture.
And no Error will show up because it's likely the .each will execute before your angular app runs.
As of June (version 1.8), the gist-embed project is now a jQuery plugin.
var $code = $('<code data-gist-id="474f6d7839fccffc4b2a"/>');
$code.appendTo('body').gist();
Basically you have to trigger "gist()" on the dom elements.
Try this, it worked for me very well.
// register trigger gist on every template include
$rootScope.$on('$includeContentLoaded', function() {
// initialize gist on new elements
angular.element(document).ready(function() {
if (typeof(angular.element(document).gist) === 'function') {
angular.element('[data-gist-id]').gist();
}
});
});
I put together a small library hoping to solve the problem.
Check it out : https://github.com/pasupulaphani/angular-gist-embed
Chekout this angular module : https://github.com/kiran3807/another-angular-gist-embed
This allows you to include the gists in your angular project in the form of a directive, one of the attributes for which is the gist-id :
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="path/to/another-angular-gist-embed.js"></script>
<script>
angular.module('example',['another-angular-gist-embed']);
angular.module.controller('exampleCtrl',['$scope',function($scope){
$scope.gistId = 'a85770344febb8e30935';
}]);
</script>
</head>
</head>
<body ng-app="example">
<div ng-controller="exampleCtrl">
<!-- This loads a gist with a specific id-->
<gist-embed data-gist-id="gistId"></gist-embed>
</div>
</body>
</html>
Declaration : I am the author of this module

How to register existing elements with Angular?

Fairly new to Angular and working inside of an existing code base.
Basically, there's an element that exists within the root document (index.html) that already exists in the html before the Angular library loads. Because of this, the ng-click directive isn't registered.
Is there an easy way that I can pass Angular a reference to the element in question and have it register that as one of its own?
Sample code (obviously missing parts, just to illustrate Angular loads after):
<html>
<body ng-app="allMyCookiesApp">
<a ng-click="giveGeuisACookie()">GIMME</a>
<script src="angular.js"></script>
</body>
</html>
I'd like to get a cookie when I click GIMME.
ng-app will bootstrap everything inside it once angular loads. This includes compiling and linking the ng-click in your example. So I think the real problem may be elsewhere.
The biggest omission from this example is any controller. I expect you are missing a controller that can place the giveGeuisACookie method on the correct scope to be used by ng-click. For example
angular.module('allMyCookiesApp', [])
.controller('geuisCtrl', function($scope) {
$scope.giveGeuisACookie = function() {
// Cookie time
};
});
would define your module for ng-app and register a controller for it. This controller will add the giveGeuisACookie function to its scope.
<html>
<body ng-app="allMyCookiesApp" ng-controller="geuisCtrl">
<a ng-click="giveGeuisACookie()">GIMME</a>
<script src="angular.js"></script>
</body>
</html>
tells angular to use the controller so that ng-click will have access to the correct method.
If this is not the problem it may be worth adding a jsfiddle with a working (or not) example of what you are doing.

Javascript single page architecture with module autonomy

I just started this HTML5 project where we decided to make it a single page architecture by leveraging jQuery $.load() method. Unfortunately, as soon as the JS started to grow, we quickly started running into issues where the modules loaded into the master dashboard have no knowledge of their parent.
The architecture looks like this:
dashboard.html (master file)
moduleA.html
moduleA.js
moduleB.html
moduleB.js
moduleC.html
moduleC.js
Since we decided to also keep the JS as separate files, we are having to load all JS files through dashboard.html in order to invoke them individually when modulex is loaded.
So when loading moduleA.html into the dashboard we have to call its corresponding JS. To do this we simply wrote the JS using a Module Pattern so we can easily invoke it by doing a function call, like:
<script>
moduleA
</script>
or this if we want to access a specific property of this member.
<script>
moduleA.someMethod();
</script>
Now, I know there are is gotta be a nicer way of doing this, right? I hate having to have script tags in the HTML modules in order to load its corresponding JS file.
Another limitation of this is the fact that we no longer can work on modules individually, since the scripts and CSS invocation happens on the parent (dashboard.html) so certainly when moduleA.html is loaded directly, it is pure HTML with no script or CSS.
I looked through the other questions but I didn't see anyone with the same problem.
I looked at AngularJS, EmberJS, KO.JS and BoilerPlateJS but none of them addresses what we are trying to accomplish. The only one that has a similar single page concept is jQuery Mobile but I don't know if you can switch from jQuery to jQuery Mobile and everything remains working.
Has anyone face this issue yet? Is there a solution or would I have to go with a custom solution.
Thanks!
I could argue about AngularJS with you. It is exactly what you need
dashboard.html is layout with some directives attached, but power lies in AngularJs if you use ng-view directive
here is example:
dashboard.js
var app = angular.module("modularApp",[]);
app.config(['$routeProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
controller:'HomeCtrl',
templateUrl:'templates/home.html'
});
$routeProvider.when('/moduleA', {
controller:'ModuleACtrl',
templateUrl:'templates/moduleA.html'
});
$routeProvider.when('/moduleB', {
controller:'ModuleBCtrl',
templateUrl:'templates/moduleB.html'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
templates/dashboard.html
<html ng-app="modularApp">
<head>
<!--.... include angular minified js file and what else you need...-->
<script type="text/javascript" src="dashboard.js"></script>
<script type="text/javascript" src="moduleACtrl.js"></script>
<script type="text/javascript" src="moduleBCtrl.js"></script>
</head>
<body>
<a ng-href="#/moduleA">Open Module A View</a>
<a ng-href="#/moduleB">Open Module B View</a>
<!-- Add widgets header menus .... -->
<ng-view></ng-view>
</body>
</html>
moduleACtrl.js
var app=angular.module("modularApp");
app.controller("ModuleACtrl",function($scope){
$scope.scopeValue="Hellow from view";
});
moduleBCtrl.js
var app=angular.module("modularApp");
app.controller("ModuleBCtrl",function($scope){
$scope.scopeValue="Hellow from another view";
});
templates/moduleA.html
<div>{{scopeValue}} in module A</div>
templates/moduleB.html
<div>{{scopeValue}} in module B</div>
You can do more complex things with angular then just this. All depends on your needs. Do you have any special requirements :)
Also, you could create your own directive, like ng-view and use your own $route service and $routeProvider so you can add css and javascript you want to dynamically load when some rute match url.
so instead of above routing table, you could have
app.config(['$myRouteProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
javascript:'javascript/dashboard.js',
templateUrl:'templates/dashboard.html',
cssfile: 'css/dashboard.css'
});
$routeProvider.when('/moduleA', {
javascript:'javascript/moduleA.js',
templateUrl:'templates/moduleA.html',
cssfile: 'css/moduleA.css'
});
$routeProvider.when('/moduleB', {
javascript:'javascript/moduleB.js',
templateUrl:'templates/moduleB.html',
cssfile: 'css/moduleB.css'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
But that is, pardon on my French, stup. There are couple libs I tried in ruby on rails to acheive similar, but backend is rendering content, or just part of content. But I'm not sure which backend you are using and are you interested to switch to rails anyway.
DomController in BoilerplateJS does what you need, without using any custom HTML attributes. Your dashboard.html can just have place holders where you want to inject your components. I'm just pulling out some html below from BoilerplateJS index.html to show how it works:
<body>
<section id="page-content">
<header>
<section class="theme"></section>
<section class="language"></section>
</header>
<aside>
<section class="main-menu"></section>
</aside>
</section>
</body>
theme, language and main-menu sections above are just place holders in to which relavant components would be injected by the DomController. The DomController can be now used to register the components with appropriate selectors as below:
//scoped DomController that will be effective only on $('#page-content')
var controller = new Boiler.DomController($('#page-content'));
//add routes with DOM node selector queries and relavant components
controller.addRoutes({
".main-menu" : new MainMenuRouteHandler(context),
".language" : new LanguageRouteHandler(context),
".theme" : new ThemeRouteHandler(context)
});
controller.start();
Above code is extracted from "/boilerplatejs/src/modules/baseModule/module.js"

Categories