Using methods in html template angular 2+ - html

What is the difference between using methods in html template that return true or false, and writing directly these conditions in html template angular 2+?
It is particularly interesting how often the first and the second method will be called?
example:
<div *ngIf="array && array.length && (array.property === true)">test</div>
or
<div *ngIf="isArrayProperty()">test</div>
public isArrayProperty() {
return array && array.length && (array.property === true);
}

The primary difference as Alexander Staroselsky has pointed out is maintainability and readability. In general logic should reside within your type script files, and not within your view. The more you can break out logic and view the easier your site will be to maintain.

Related

How to migrate jQuery functions and events in gatsby?

I am currently migrating an old but still beautiful website to Gatsby PWA.
The old website was built purely in HTML and jQuery, and it has many beautiful animations with jQuery functions.
Technically, I succeeded in importing some external scripts including jQuery(v3.3.7) and Bootstrap(3.3.1) by customizing html.js.
And also I updated some attribute names like class to className, style - string to object, etc.
What I think a bit difficult is to use jQuery functions with events like onmouseover in the old HTML files.
For example,
...
<div className="section">
<div className="block_information" id="block_information">
<div className="row first_row">
<div className="col-md-2 col-xs-12 icon_block_information top">
<div className="svg_text" onmouseover="runSmile()">
~~~~~~~~~~~~~~~~~~~~~~~~
<svg viewBox="0 0 80.25 80.25">
...
<g id="icon_smile_1">
<path
id="icon_smile"
className="cls-2"
...
And runSmile function looks like,
function runSmile() {
window.ks = (function () {
function z(a) {
return "undefined" !== typeof a;
}
function v(a, b) {
return a && 0 == a.indexOf(b);
}
function N(a) {
if (!isFinite(a)) throw "non-finite value";
}
function O(a) {
if (14 >= a) return 16;
(a = X[a]) || (a = 0);
return a;
}
function D(a) {
return 0 <= a ? Math.pow(a, 1 / 3) : -Math.pow(-a, 1 / 3);
}
...
document.ks = ks;
(function (ks) {
ks.animate(
"#icon_smile",
[{ p: 6, t: [0, 1000], v: [0, 360], e: [[0], [0]] }],
{
autoplay:
document.location.search
.substr(1)
.split("&")
.indexOf("autoplay=true") < 0,
},
);
})(ks);
}
In this case, can I use the jQuery functions with only small updates and also without updating event attributes like onmouseover to onFocus?
If I have to update the jQuery functions and event attributes, what should I do?
Thanks in advance.
onmouseover should be replaced by onMouseOver or onMouseEnter/onMouseLeave.
However, I would discourage you from importing jQuery and Bootstrap into a React project (really, don't do it).
jQuery and Bootstrap point and manipulates directly the real DOM, while React creates and manipulates a virtual DOM (vDOM). Because of that, React will never be aware of changes that jQuery does to the DOM and vice-versa, which translates into hydration issues. Practically, this means that your components (or part of them) may not be rendered when you want or in your different use-cases, especially when you perform some kind of navigation through pages, losing control of your code-flow.
In addition, because of that different way of working (DOM vs vDOM), jQuery functions applied into React environment will be never unmounted. This may sound meaningless but your resources will keep getting accumulated and eventually your site will become extremely slow, especially for users that remain more than X seconds.
Both (jQuery and React) have different purposes and you shouldn't mix them, it will lead you to huge caveats and headaches.
Moreover, window in Gatsby needs to be treated specially (like any other global objects, like document) because of the SSR (Server-Side-Rendering), where there's no window because it's not even defined yet. Depending on your triggers and use-cases, you may need to wrap it inside:
if(typeof window !== 'undefined'){
// your window stuff
}
If you still keep working with jQuery in a React environment you can follow: https://reactjs.org/docs/integrating-with-other-libraries.html
Where it provides some useful hints to unmount all the jQuery functions.
Regarding Bootstrap, I would recommend using the React-based version to avoid the same hydration issues that I explained before.

Angular Conditional Views?

I have inherited a mess of a Angular project. I've never really messed with Angular too much but know MVC well enough to feel like I can learn. My question is I have a property of a JSON object that I want to return a different views for. (one is an archived state and one is a non-archived state) As they both have different view templates, how would I return the non-archive template if the json.status == 'archived'
I have the following as my current StateProvider's templateURL property.
templateUrl: appConfig.viewPath + 'non-archived.html?v=' + appConfig.version
should I just return multiple template urls here? Or do I have to create a whole new url path?
Thanks!
I've gone down this road a few times, I don't think I've found the optimal way yet, but I've learned a few things.
It really all depends on when you have access to your json-object. You can pass a function to templateUrl, and send in a service.. (A service that returns your current json-object could be great, but how would you update it? Probably when you change route right? Then you have a egg-hen problem. You can't decide route until you have the json-object, but you don't have the json-object until you change route.)
But IF you have access to the json-object you could do something like this:
templateUrl: function(){
var tpl = (json.status == 'archived') ? 'archived.html?v=' : 'non-archived.html?v=';
return appConfig.viewPath + tpl + appConfig.version
}
But my guess is that you don't have access to the json-object until after the route has loaded.
Then I'd say the easiest way (but maybe not so pretty) is to have just one template. $scope.json = json in the controller:
<div ng-if="json.status == 'archived'">
<h1>ARCHIVED</h1>
...
</div>
<div ng-if="json.status != 'archived'">
<h1>NOT ARCHIVED</h1>
...
</div>
Or if you think that is too cheap, declare two routes. The whole "create a whole new url path" is not as painful as you might think. It'll be considerably less complex than trying to wedge out a value from a route before it has loaded.
1: Try this. send json.status in $stateParams and apply condition inside stateProvider :
$stateProvider.state('home', {
templateProvider: ['$stateParams', 'restService' , function ($stateParams, restService) {
restService.getJson().then(function(json) {
if (status.status == 'archived') {
return '<div ng-include="first.html"></div>';
} else {
return '<div ng-include="second.html"></div>';
}
})
}]
});
2 : or simply in view you can try this:
<div ng-if="json.status == 'archived'">
<h1>ARCHIVED</h1>
...
</div>
<div ng-if="json.status != 'archived'">
<h1>NOT ARCHIVED</h1>
...
</div>

In what contexts is interpolation legal in Angular, and why?

I know that Angular's string interpolation normally operates on expressions inside Handlebars-style {{ double curly braces }}, and by observation I know that I can use it in contexts like
text outside HTML tags: <span>{{ 'string literal expression ' }}</span>
attribute values inside HTML tags: link
and not to generate attributes themselves, i.e.
<a {{ 'href="/link/to/elsewhere"' }}>link</a>
does not get interpolated.
What I'm curious about is why: what are the rules on where interpolation does and doesn't happen, where this is documented, and what the design considerations or constraints are that led to this.
I guess this is because the document is parsed as HTML by the browser before Angular sees it, so the structure is dictated by HTML and the {{ stuff }} has to appear in places that are well-formed according to HTML even before interpolation happens. But I'd appreciate knowing the whole story.
What are the rules on where interpolation does and doesn't happen ?
Angular.js uses $compile service to compile a piece of DOM. The docs says:
The compilation is a process of walking the DOM tree and matching DOM elements to directives.
In the source code of compile.js there is a function collectDirectives, I trimmed it to show only the relevant code:
function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
var nodeType = node.nodeType;
// ....
switch(nodeType) {
case 1: /* Element */
// ....
// iterate over the attributes
for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
// ....
addAttrInterpolateDirective(node, directives, value, nName);
// ....
}
// ....
break;
case 3: /* Text Node */
addTextInterpolateDirective(directives, node.nodeValue);
break;
case 8: /* Comment */
// ....
break;
}
directives.sort(byPriority);
return directives;
}
As you can see, $compile search for interpolated content only inside attributes and text nodes when it iterates a piece of DOM.
Those functions, addTextInterpolateDirective and addAttrInterpolateDirective "translate" the interpolated expression into directives that $watch interpolated expressions and update the DOM element.
Where this is documented?
The compilation phase is documented here: http://docs.angularjs.org/guide/compiler
It's getting better every day but still some in-depth stuff are not clear until you read the source code itself. I guess some things are just too compilcated to explain without showing the code.
What the design considerations or constraints are that led to this?
I guess there are two reasons:
Angular operates on DOM nodes rather than strings, If angular needed to interpolate attributes or elements then It should operate on html strings which is probably bad for performance.
There is no major use case for such things.
If you still want to interpolate everything, do that kind of magic inside a directive:
An example:
app.directive('myAnchor',function(){
return {
restrict: "E",
transclude: true,
link: function(scope,element,attrs,ctrl,$transclude) {
attrs.$observe('interpolate', function(val){
var e = angular.element("<a " + val + "></a>");
$transclude(scope,function(clone){
e.append(clone);
});
element.replaceWith(e);
});
}
};
});
Be sure to read this:
What is the difference between the $parse, $interpolate and $compile services?

Umbraco Querying from Macro Script?

Umbraco Version = 6.0.3
I'm trying to do some seemingly simple stuff in a macro scriptlet. Basically, I want to loop through all of the visible child content that is not a category:
#inherits umbraco.MacroEngines.DynamicNodeContext
#{
var subs = Model.Children.Where("Visible && DocumentTypeAlias != \"Category\"");
}
<span>Count: #subs.Count()</span>
#if (subs.Any())
{
<ul>
#foreach (var sub in subs)
{
<li>
#sub.Name
</li>
}
</ul>
}
If I take out the "Visible" portion of the where clause, it works correctly (with the exception of displaying content marked as hidden). I can also use "Visible" on it's own by removing the "DocumentTypeAlias", but then all visible content including categories are displayed.
I also tried using strongly typed queries #Model.Content.Children.Where(x => x.IsVisible() && x.DocumentTypeAlias != "Category") but I get an error about not being able to use lambda functions with dynamically typed content.
Ideas?
Two things:
The DynamicNode Where clause uses a parameter syntax.
Use NodeTypeAlias to check the document type.
Example:
var subs = Model.Children.Where("Visible && NodeTypeAlias != #0", "Category");
Here are a few Umbraco razor resources:
Umbraco 4.7 Razor Feature Walkthrough. It's a 8-part series and it's pretty informative. Don't be put off by the version reference, it's still valid for Umbraco 6.
Razor DynamicNode Cheat Sheet.

mootools 1.11 div contains checked checkbox

how can mootools 1.11 determine if a div contains any checked check boxes?
tried all kinds of variations using $ $$ $E $ES getElements and css selectors, its just not returning true if this div contains no tick boxes
var ticked = $(sId).getElements('[checked=checked]');
if($chk(ticked)){alert('yo');}else{unticked = true;}
"checked" is a dynamically assigned DOM property (which is a boolean), and accessing the attribute only returns the value that was there when the page loaded (or the value you placed when using setAttribute).
Also, as MooTools 1.11 does not have complex selectors (attributes can not be filtered directly within $$) and the filterByAttribute function only accepts direct string comparison, this is your only (and best!) option:
$(sId).getElements('input').filter(function(input) {
return /radio|checkbox/.test(input.getAttribute('type')) && input.checked;
})
note: I added radio just for completeness, the filter loop would have to be run anyways to verify the checked status.
If you want to simplify the process and be able to reuse the code (the MooTools way), you can also mix-in the checked filter into Elements like this:
Element.extend({
getCheckedInputs: function() {
return this.getElements('input').filter(function(input) {
return /radio|checkbox/.test(input.getAttribute('type')) && input.checked;
});
}
});
and then your selection call is reduced to:
$(sID).getCheckedInputs();
From The Documentation:
$(sId).getElements("input:checked");
for 1.1
console.log( $('id').getProperty('checked') );