I am implementing a Search feature in my AngularJS tutorial application. So, whenever a user types in the Search <input> field, I want to change my document's <title>.
For this, I am using query model with ng-bind-template in my document's <title> to avoid double curly braces {{}} flicker effect when application loads.
Following is my code for reference.
<!DOCTYPE html>
<html lang="en" ng-app="phonecatApp" ng-controller="PhoneListCtrl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="icon" href="/assets/img/fav.png">
<title ng-bind-template="Phonecat | {{query}}">Phonecat</title>
<link rel="stylesheet" href="/assets/css/app.css">
<script src="/assets/js/angular/angular.min.js"></script>
</head>
<body>
<div>
<span>Search: </span><input ng-model="query" />
</div>
<ul>
<li ng-repeat="phone in phones | filter:query">
<span>{{phone.name}}</span>
<p>{{phone.snippet}}</p>
</li>
</ul>
<p>Total number of phones: {{phones.length}}</p>
<script src="/assets/js/app.js"></script>
</body>
</html>
Here, my <title> tag has ng-bind-template directive with query model & pre-defined content,
Phonecat
Now, when page loads document <title> is set to,
Phonecat |
Instead of just "Phonecat".
I don't want ng-bind-template to evaluate & change my document's <title> if query model is EMPTY. If query model is EMPTY, it should just display the initial content (Phonecat in this case) as document's Title & when the query model is updated & NOT EMPTY, it should update the Title (i.e. Phonecat | nexus mobile).
It will be great if someone can explain how to approach this.
Thanks!
You can use the ternary operator inside ng-binding to conditionally build the title:
<title ng-bind="query ? 'Phonecat | ' + query : 'Phonecat'">Phonecat</title>
Alternatively:
<title>{{ query ? 'Phonecat | ' + query : 'Phonecat'}}</title>
Related
In this HTML:
<ol>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four
<ol>
<li>Us</li>
<li>They
<ol>
<li>Monkey</li>
<li>Cat</li>
<li>Elephant</li>
<li>Dos</li>
</ol>
</li>
<li>You</li>
<li>She</li>
</ol>
</li>
</ol>
how do I target those list-items that contain the nested list? In this particular example, how do I target the list-items with the words “Four” and “They”?
Since the html will change constantly, I am looking for an option that do not depend on classes or other method that require me to alter the html in order to stylize it.
It is possible to target theses list-items without touching the HTML? It seems to me that it might be hard/impossible since there is no a CSS parent selector. Any ideas?
It's not that hard you just have to add an id to the specific item in the list or a class to the group of items in the list it depends on what you want to modify.
Example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<ol class = "list">
<li id = "one">One</li>
<li id = "two">Two</li>
<li id = "three">Three</li>
<li id = "four">Four</li>
</ol>
</body>
</html>
Now in your css file you just have to targe what you want to give style. If its an id you have tou use a "." and the name of the id like: ".one" or if its a class you have tu use the "#" like this: "#list"
I've created a server-side react app, where it would return html as shown below:
const html = renderToString(<App />);
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>A Cool Page</title>
<link rel="stylesheet" href="${ROOT}/static/index.css">
</head>
<body>
<div id="root">${html}</div>
<script src="${ROOT}/client-bundle.js"></script>
</body>
</html>
I read a lot of people have been using react-helmet to manage the content in head. I'm wondering what's the benefit of using it, when I can just directly include as shown above.
A major benefit of react-helmet is when you have multiple components in a tree with <head> tags, and you have <meta> tags with the same attributes/values.
For instance, if on your index page component you have:
const html = renderToString(<App />);
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta name="description" content="This is the index page description">
<title>A Cool Index Page</title>
</head>
</html>
But then on a leaf page component, you also have a <head> tag containing meta tags:
<html>
<head>
<meta name="description" name="This is the unique leaf page description">
<title>A Cool Leaf Page</title>
<link rel="stylesheet" href="${ROOT}/static/index.css">
</head>
</html>
Notice between our two page components there are two meta tags with the same attribute value name="description" in our tree. You might think this could lead to duplication, but react-helmet takes care of this problem.
If someone ends up on the leaf page, react-helmet overrides the index/site-level description meta tag and renders the lower-level one, the one specifically for the leaf page.
It will also contain the viewport meta tag, since it did not have to be overwritten.
Because of react-helmet, on the leaf page, the <head> would appear as follows:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta name="description" name="This is the unique leaf page description">
<title>A Cool Leaf Page</title>
<link rel="stylesheet" href="${ROOT}/static/index.css">
</head>
</html>
react-helmet allows to set meta tags that will be read by search engines and social media crawlers. This makes server-side rendering and React Helmet a dynamic duo for creating apps that are SEO and social media friendly.
eg:
import { Helmet } from 'react-helmet';
<Helmet>
<title>Turbo Todo</title>
<meta name="description" content="test on react-helmet" />
<meta name="theme-color" content="#ccc" />
</Helmet>
Both methods should work. But with react-helmet, the head is also treated as a component and is more react-like. Also, although it's unusual, you may bind some props or states with the meta-data to implement a dynamic head. One scenario is switching between different languages.
React Helmet also allow you to modify classes outside the scope of your render function.
For example, if you want to modify your <body> tag dynamically, you could do the following:
<Helmet>
<body className="dynamic-class-for-body-on-this-view" />
</Helmet>
React Helmet is a reusable React component that will manage all of your changes to the document head.
For example, if you want to change the title and meta description of every page according to your SEO, you could do the following:
<Helmet>
<title>Your Title</title>
<meta name="description" content="Description of your page" />
</Helmet>
I specifically use Helmet for meta tags and to also change the style of a 3rd party component that isn't editable.
<Helmet>
<script type="text/javascript">
{`
window.addEventListener('load', function () {
document.querySelectorAll('.noEditStars > span').forEach(span => {
span.style.cursor = 'pointer';
});
}, false);
`}
</script>
</Helmet>
I am trying to display a plain html/css loading spinner on first load in my Angular APP. The spinner code is included in my index.html.
However, the dom seems not to be rendered until my angularjs APP starts kicking in, causing a very lengthy display of a white screen until this finally happens. Is there any way to prevent that?
I would like to understand how to load my plain html/css spinner right after the css code in the head is done loading so as to improve user experience.
Test on webpagetest.org seem to confirm this diagnosis (the /settings, /introductions, /menus lines are all calls to an external API done by an AngularJS service before render):
Here is a simplified version of my build code:
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<title ng-bind="($title || 'Home') + ' - WalktheChat'">WalktheChat</title>
<link rel="stylesheet" href="styles/lib.css">
<link rel="stylesheet" href="styles/app.css">
</head>
<body>
<div id="base-container" ng-controller="Shell as main">
<div ng-include="'app/layout/header.html'"></div>
<div id="content" ui-view ng-cloak autoscroll="true"></div>
<div ng-include="'app/layout/footer.html'"></div>
</div>
<!-- This is the spinner I would like to display on first load -->
<div ng-show="::false" class="spinner-container">
<div class="spinner sk-spinner sk-spinner-pulse"></div>
</div>
<script src="js/lib.js"></script>
<script src="js/app.js"></script>
</body>
</html>
whatever the complexity of your application,all your controllers are within the same angular application, all scopes within the same application inherits from the same root, whatever you define on the $rootScope will be available to all child scopes.
we have two ways to resolve this problem:
use $broadcast(), $emit() and $on() that facilitate event driven publisher-subscriber model for sending notifications and passing data between your controllers.(professional solution)
declare $rootScope variable and watching changement.(simple way)
It turns out the problem was coming from "render-blocking javascript", I had to add the "async" tag to my JS to fix it.
When adding async to both my lib.js and app.js, I had an issue with app.js loading before angular scripts were loaded (thus causing the APP to throw an error). In order to solve this issue, I combined my lib.js and app.js into one single file and then added the async tag.
My final build code looks like that (the magic happens on the final "script" tag):
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<title ng-bind="($title || 'Home') + ' - WalktheChat'">WalktheChat</title>
<link rel="stylesheet" href="styles/lib.css">
<link rel="stylesheet" href="styles/app.css">
</head>
<body>
<div id="base-container" ng-controller="Shell as main">
<div ng-include="'app/layout/header.html'"></div>
<div id="content" ui-view ng-cloak autoscroll="true"></div>
<div ng-include="'app/layout/footer.html'"></div>
</div>
<!-- This is the spinner I would like to display on first load -->
<div ng-show="::false" class="spinner-container">
<div class="spinner sk-spinner sk-spinner-pulse"></div>
</div>
<!-- This app.js now also contains lib.js from my question !-->
<script src="js/app.js" async></script>
</body>
</html>
I am trying to build a tab set that would dynamically change on user action using bs-tabs angularstrap directive and ng-repeat (Say initially the tabs were a,b,c. On some user action it should change to x,y,z)
I am trying to do this by pointing the ng-repeat to a new array object on an user action say a click of a button.
Instead of the tab set getting refreshed, I am noticing a strange behavior
Ive recreated it in this plnkr, please have a look at it,
http://plnkr.co/edit/bpKDx56bieIshKaedzv6?p=preview
<!DOCTYPE html>
<html ng-app="angularjs-starter">
<head lang="en">
<meta charset="utf-8">
<title>AngularStrap - Tab directive</title>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" rel="stylesheet">
<link href="//mgcrea.github.com/angular-strap/css/prettify.css" rel="stylesheet">
<!-- required libraries -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
<script src="//mgcrea.github.com/angular-strap/js/angular-strap.js"></script>
<!-- optional libraries -->
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.0.0/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fastclick/0.6.0/fastclick.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/prettify/r224/prettify.js"></script>
<link rel="stylesheet" href="style.css">
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div data-fade="1" ng-model="tabs.activeTab" bs-tabs>
<div ng-repeat="tab in tabs" data-title="{{tab.title}}"><p>{{tab.content}}</p></div>
</div>
<button type="button" class="btn btn-primary" ng-click="changeTabs()">Show different set of tabs</button>
</body>
</html>
Looking at the code it seems that the tab directive observes the active tab value and refreshes only the tab content using transclusion, whereas the tab title is only assigned initially.
I think the only way to change title dinamically is creating a new directive that creates a tab directive dinamically, initializing it with the fresh values.
I am still learning the tricks to jQuery mobile and have been having a problem with the zooming in and zooming out of a picture/image on a data-role="page." Is there a way to make the pinch/zoom work on an image on the iPhone using jquery mobile? Cant get it to work on the iOS Simulator. Here is my code.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery Mobile Web App</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=2" name="viewport">
<link href="jquery.mobile-1.0a3.min.css" rel="stylesheet" type="text/css"/>
<script src="jquery-1.5.min.js" type="text/javascript"></script>
<script src="jquery.mobile-1.0a3.min.js" type="text/javascript"></script>
<!-- This reference to phonegap.js will allow for code hints as long as the current site has been configured as a mobile application.
To configure the site as a mobile application, go to Site -> Mobile Applications -> Configure Application Framework... -->
<script src="/phonegap.js" type="text/javascript"></script>
</head>
<body>
<div data-role="page" id="page">
<div data-role="header">
<h1>Page One</h1>
</div>
<div data-role="content" style="padding:0;">
<img src="coffee.gif" width="320" height="480" alt="coffee">
</div>
<div data-role="footer">
<h4>Page Footer</h4>
</div>
</div>
</body>
</html>
Thanks so much for your help. Much appreciated.
-bob
edit the "viewport" in meta tag with this
<meta name="viewport" content="user-scalable=yes, initial-scale=1, maximum-scale=2, minimum-scale=0.5, width=device-width, height=device-height, target-densitydpi=device-dpi" />
It's the viewport metadata property that controls those settings.
Follow this to see how to enable pinch & zoom on JQM iOS (shouldn't really matter that you are using PhoneGap).
Hope this helps.
When jQuery Mobile renders a page, it adds the following meta tag to
the head of the document.
<meta content="width=device-width, minimum-scale=1, maximum-scale=1" name="viewport">
It is the minimum-scale=1, maximum-scale=1 part of
the tag which disables the pinch zoom. What we need to do is modify
the $.mobile.metaViewportContent variable. We can do this using the
following code.
$(document).bind('mobileinit', function(){
$.mobile.metaViewportContent = 'width=device-width';
});
If we want to restrict the amount of zooming, we can use the following:
$(document).bind('mobileinit', function(){
$.mobile.metaViewportContent = 'width=device-width, minimum-scale=1, maximum-scale=2';
});