Alternative or better approach for *NgIf - javascript

Hi I have several *NgIf conditions in my template. Based on the NgIf I display/render my components(different type of form) in the template. Example in one of my function (below)
private _onClick(cell:any){
this._enableView = false;
this._enableCreate = true;
this._enableDelete = false;
this._enableEdit = false;
}
Which is to enable my create form in the template and hide other forms if its there. But doing so feel like bit wrong or redundant to me. Is there any better approach or suggestion instead of this approach?

If it is possible to have a single state as suggested by Leguest I would recommend ngswitch used like this:
// Syntax for ngSwitch
<div [ngSwitch]="state">
<div *ngSwitchCase="'create'"> ... </div>
<div *ngSwitchCase="'view'"> ... </div>
<div *ngSwitchCase="'edit'"> ... </div>
<div *ngSwitchCase="'delete'"> ... </div>
<div *ngSwitchDefault> ... </div>
</div>
Otherwise if you are using Angular 4.x you can take advantage of ngIf else:
// Syntax for ngIf/Else
<div *ngIf=”condition; else elseBlock”>Truthy condition</div>
<template #elseBlock>Falsy condition</template>

I am not sure is it better or worse, but you can have one state property e.g. this.state, that contains string:
JS
private _onClick(cell:any){
this.state = 'create'
}
HTML
<div *ngIf="state == 'create'">
// create form
</div>
<div *ngIf="state == 'view'">
// view form
</div>
<div *ngIf="state == 'edit'">
// edit form
</div>
<div *ngIf="state == 'delete'">
// delete form
</div>
So you replace part of your code into templates, I hope it reduce your js codebase

Related

How to set a class name dependant on another attribute of the same element in Svelte?

I want to set a conditional class based on an attribute of the same element so that I can stay dry. At first I got this:
<div class="hidden md:flex items-center space-x-3">
Farm
LeaderBoard
WafBox
Buy
Info
</div>
Now I would like this:
<div class="hidden md:flex items-center space-x-3">
Farm
LeaderBoard
WafBox
Buy
Info
</div>
Then I would simply have to check the attribute of href in my function isActive. But here this does not seem to have the right informations inside. Is there a way to do it ? It would clean my code a lot
Edit: isActive() would look like this:
<script>
function isActive(element) {
return 'Active' if (currentPageName == element.attr('href'))
}
</script>
One problem with your approach is that both in
LeaderBoard
and the proposed answer using the class:directive
<a href="#Index" class:active-link={isActive('Index')}>Index</a>
is that the function will only run once, at the first render and then never re-execute, not even when currentPageName changes.
The most obvious, straight solution would be to simply ditch the function call and use the class:directive like this:
<a href="#Index" class:active-link={currentPageName == 'Index'}>Index</a>
this will make sure the classes change as currentPageName changes.
When declaring the function with the arrow syntax and making it reactive by adding $: it looks like alternatively to using the class:directive (which checks if value is truthy/falsy) the classname could be directly set inside the class="" attribute as well
A REPL
<script>
let currentPageName = 'Index'
$: isActive = (linkText) => {
if (linkText === currentPageName) return 'active-link'
// else if (...) return 'other-class-name' // possible class name switch
else return ''
}
</script>
<div class="">
Index
</div>
<div class="">
Leaderboard
</div>
<br>
<button on:click={() => currentPageName = 'Leaderboard'}>change currentPageName</button>
<style>
.active-link {
color: purple;
}
</style>

How to write multiple HTML divs in a JS function

So I wanna print an object to my page and I have no idea how to write the code in JS so that on my page it prints multiple divs for each object.
What I wanna do is insert this
<div class="cv-block">
<div id="parent_div_1">
obiect.firstn
obiect.lastn
</div>
<div id="parent_div_2">
obiect.date
</div>
obiect.message
</div>
into this java script function
function afisare (lista) {
var randuri = "";
lista.forEach(function (obiect) {
randuri += ;
});
$("#obiect").html(randuri);}
Thank you in advance for your time.
best way to do this is using template literal which is supported by ES6.
if you want to use it in older browser you should use babel.
$("#obiect").html(`<div class="cv-block">
<div id="parent_div_1">
${obiect.firstn}
${obiect.lastn}
</div>
<div id="parent_div_2">
${obiect.date}
</div>
${obiect.message}
</div>`)
also there is ES5 code for it.
$("#object").html("<div class=\"cv-block\">\n <div id=\"parent_div_1\">\n obiect.firstn\n obiect.lastn\n </div>\n\n <div id=\"parent_div_2\">\n obiect.date\n </div>\n\n obiect.message\n\n </div>");

Angular JS view hasn't been updated properly

I have found an issue in AngularJS which relates to wrong update of view. It occurs from time to time. The problem is when model gets a new value, view is not updated by new model value, but old value is appended by new model value.
While troubleshooting I checked that model contains a correct value.
Here is a view.
<div class="container">
<div ng-repeat="p in point" id="{{'point-' + p.Id}}" class="{{p.BackgroundClass}}">
<div class="point-number">{{p.Id}}</div>
<div class="{{p.ImageClass}}"></div>
<div class="point-amount">{{p.Amount}}</div>
<div class="point-quantity">{{p.Quantity}}</div>
</div>
</div>
Controller code which contains SignalR events processing:
wetApiHubProxy.on('updatePointState', function (pointId, backgroundClassProp, imageClassProp) {
pointsService.getPointById(pointId).then(function (point) {
point.BackgroundClass = backgroundClassProp;
console.log('imageClassProp ' + point.ImageClass);
point.ImageClass = imageClassProp;
});
});
p.ImageClass is changing quite often. Changes/updates of view work in a correct way until sometimes occurs concatenation of old and new value.
Old p.ImageClass value is "point-state-configure".
New p.ImageClass value is "pump-state-off".
As a wrong result I have, where ImageClass contains concatenated values:
<div ng-repeat="p in points" id="point-4" class="point point-off" role="button" tabindex="0" style="">
<div class="point-number ng-binding">4</div>
<div class="point-state-configure pump-state-off" style=""></div>
<div class="point-amount ng-binding">926.93</div>
<div class="point-quantity ng-binding">417.35 L</div>
</div>
I have tried to call $scope.$apply() and $evalAsync, but that was hopeless. The strangest thing that issue occurs spontaneously. The only constant condition it's when $rootscope contains bigger amount of child scopes. Can anyone tell what place to dig and how to get rid of this problem?
class attribute is not intended to be used this way. You should use the ng-class directive instead.
I've created an example for you: https://jsfiddle.net/coldcue/o7q6gfs4/
JavaScript
angular.module('testApp', [])
.controller("TestController", function($scope) {
// Initialize the value
$scope.state = "state-blue";
// Change class on click
$scope.click = function() {
$scope.state = ($scope.state === "state-blue") ? "state-red" : "state-blue";
}
});
HTML
<div ng-controller="TestController">
<div ng-class="state">
Some label
</div>
<input type="button" ng-click="click()" value="Click me">
</div>
But there are many more ways to use ng-class, read more here: https://docs.angularjs.org/api/ng/directive/ngClass

knockout condition in HTML page

Below is my HTML binding to display the records. I, have apply knockout js to perform the condition check as you can see the IF statement.
I want to use count++ as a knockout variable and perform the condition check.
The above code also not working for me.
Please can anyone let me know how to check the condition in knockout.
<div data-bind="foreach: GuidelinesQuestionList" id="problemcollapse">
<div data-bind="foreach: $data.SectionsSet">
<div class="primaryCaseContainer">
<div class="questionHeader" data-bind="text: $data.Heading , attr:{onClick: 'variableName.CollapseExpandCustom.ToggleSection(\''+$data.Uid.replace(/[^\w\s]/gi, '')+'\')'}"></div>
<div data-bind="attr: {id: $data.Uid.replace(/[^\w\s]/gi, '')}">
#{int count = 0;}
<div class="questionContainer" data-bind="foreach: $data.ProblemsSet">
<div data-bind="if: $data.Identified">
#{count++;}
<div>
<br><br>
<div data-bind="attr: {id: 'goalsReplaceDiv'+$data.Uid.replace(/[^\w\s]/gi, '')}"></div>
</div>
</div>
</div>
#if (count == 0)
{
<div id="divNoRecordsMessage">
<div>No Records !! </div>
</div>
}
</div>
</div>
</div>
</div>
You are mixing C# razor code with Knockout bindings. The count variable will not increment in your loop because it's evaluated before being returned to the client. Your loop is being rendered on the client.
Instead of doing that, make your divNoRecordsMessage show/hide based on a KO binding.
Something like this:
<div data-bind="visible: conditionForNoRecords">
No Records
</div>
But you should really make a custom filter for the ProblemSet array, something like this:
self.filteredProblemsSets = ko.computed(function() {
return ko.utils.arrayFilter(this.ProblemsSet(), function(item) {
return item.Identified;
});
}, viewModel);
You could then skip your if condition in the view and you would be able to easily display "No messages" when the array is empty.

How can I dynamically render both javascript data and html within the same angular curly braces ({{ }})?

I am rendering different kinds of attributes within the same html element in the following manner:
Javascript:
var dataAttribute = {
value:function(){ return 1;}
}
var listAttribute = {
value:function(){ return "<div>My Arbitrary HTML
<div>1</div>
<div>2</div>
<div>3</div>
</div>";}
}
var attributes = [dataAttribute,listAttribute]
HTML:
<div ng-repeat="attribute in attributes"> {{ attribute.value() }} </div>
How do I get the html in the listAttribute to render as HTML and not as text, while still retaining the ability to render the normal data of the dataAttribute?
You just should not. Use ng-switch directive if you want to render different things based on properties of items in your collection. ( in worst case use series of ng-if inside your ng-repeat)
Do not invent another templating engine if you already using angular, you are just confusing yourself.
Little more explanation here. You already have code that generates that html somewhere. It really better by angular directives.
<div ng-repeat="attribute in attributes" ng-switch="attribute.type">
<div ng-switch-default> {{ attribute.value() }} </div>
<div ng-switch-when="table"><my-table data='attribute.value()'></my-table></div>
<div ng-switch-when="list"><my-list data='attribute.value()'></my-list></div>
</div>
And set of directives
.directive('myTable', myTable).directive('myList', myList)
will hold all the logic to produce html from the data.
I.E. don't mix layout and data in one structure.
The solution was a combination of #vittore and #YOU's answers:
Javascript:
var dataAttribute = {
value:function(){ return 1;},
type:'data'
}
var listAttribute = {
value:function(){ return "<list-directive></list-directive>";},
type:'list'
}
var attributes = [dataAttribute,listAttribute]
HTML:
<div ng-repeat="attribute in attributes" ng-switch="attribute.type">
<div ng-switch-default> {{ attribute.value() }} </div>
<div ng-switch-when="list" ng-bind-html="attribute.value()"></div>
</div>
Thanks!

Categories