Buttons not disabled when initializing component - html

I'm using the [disabled] property to decide if button elements should be or not disabled, depending if an array.length returns 0 or not.
This is working fine after the user interacts with the component, however the buttons aren't disabled when the component is initialized and the array is empty.
typescript
constructor() {
this.macrosSelected = [];
}
html
<button
type="button"
class="btn btn-secondary"
[disabled]="!macrosSelected.length"
>
As I said, this code is enabling the button when the array has an object inside it, and disabling it once the array returns to an empty state.

As you have assigned macrosSelected = [] in your constructor then this will be the initial value of your variable. If you are assigning this variable using #Input() decorator or by a service, those will update this variable after the constructor call means second assignment. So you can simply check the length of macrosSelected variable like below.
Your template code must be like:
<button type="button" class="btn btn-secondary" [disabled]="macrosSelected.length === 0"></button>

Related

How to add disabled attribute to button in react?

Here is my code
import React from 'react'
import PropTypes from "prop-types";
export default function Button({ htmlType, type, disabled, action, ...props}) {
return (
<button type={htmlType} onClick={action}>
{props.children}
</button>
)
}
Button.propTypes = {
htmlType: PropTypes.string.isRequired,
action: PropTypes.func,
disabled: PropTypes.bool
};
I call Button component by this code
<Button disabled={true}>button title</Button>
I want to add disabled html attribute to button when disabled of props is true, how to do it ?
You could line single line if-else statements like this:
<button disabled={propsDisabled}>button title</button>
Here, propsDisabled is the variable which you can pass through the props, and it is a boolean variable which will either be true or false. I have not used disabled itself to avoid confusion but you can use the variable name as disabled.
When propsDisabled is true, the button will be dissabled, and when propsDisabled is false the button will not be disabled.
Aya, I couldn't exactly understand your question, it looks like you're trying to solve a problem, when you have a second problem in the question in the first place.
Are you using Ant components? use the disabled prop on the <Button /> component itself. (notice the capital B in the component name Button).
<Button disabled={true} />
// or (it's the same but different JSX syntax)
<Button disabled />
This is the same answer answered by the brother #Abdul Qadir.
If you're working with native HTML elements, also, you can call the disabled attribute on the <button /> element (notice the small character b in the element name button) the same way and it should work:
<button disabled={true}>I'm disabled</button>
// or (the same but different syntax)
<button disabled>I'm disabled</button>
So here are the two answers,
If you're working with Ant components:
import { Button } from 'antd';
const CustomButton = ({ disabled, children }) =>{
return <Button disabled={disabled}>{children}</Button>
}
If you're working with native HTML elements:
const CustomButton = ({ disabled, children }) =>{
return <button disabled={disabled}>{children}</button>
}

toggle component input using only template

How can I toggle an input to a component using a button, without creating a component property to hold the value?
example:
<button #componentVisibility (click)="componentVisibility.value = !componentVisibility.value" value="false">
show graph
</button>
<my-component [graphVisible]="componentVisibility.value"></my-component>
This one for example is not good because value has to be a string, and I need to toggle a boolean and pass it in.
How can I toggle a local template boolean and pass it in to a component, without creating a component property to hold it?
Note:
Doing the following throws a transpile error:
<button (click)="graphVisible ? graphVisible = false:graphVisible = true;" value="false">
show graph
</button>
<my-component [graphVisible]="graphVisible"></my-component>
Error thrown about graphVisible not being a property on the parent component.

Angular: Enable button asynchronously

I am fetching data in my angular app from a REST API. I want to enable the button of the search once the user logs in. I have added auth.service.ts which I am importing in my search navbar component. But, the button doesn't get enabled once the user logs in. The data is asynchronous so, it either remains disabled or enabled. I can't figure it out.
Here's my code:
navbar.component.ts
allowSearch: boolean = false;
buttonEnable() // this should get called every time change is detected in the input
{
if(this.authService.isAuthenticated())
{
this.allowSearch = true;
}
}
navbar.component.html
<input type="text" value="" class="form-control" (change) = "buttonEnable()" placeholder="Search..." [(ngModel)] =
"searchElement" name = "searchElement"
style = "background-color: #faf9f9" id = "searchElement" >
<div class="input-group-append" style = "background-color: #faf9f9">
<button type="button" name="button" type = "submit" [disabled] = "!allowSearch" (click) =
"openModal2(); onSearch(searchElement)"><i class="nc-icon nc-zoom-split"></i></button>
</div>
If you call to authService outside of navBar, you can get it if your service has, futhermore a method to login, a Subject. Else simply change the variable in the subscribe function.
e.g. using Subject:
LoginService(){
isLoggin:Subject<boolean>=new Subject<boolean>()
loggin(data){
this.httpClient.get(....).pipe(
tap(res=>{
if (.....)
this.isLoggin.next(true)
})
)
}
loggout(){
this.httpClient.get(....).pipe(
tap(_=>{
this.isLoggin.next(false)
})
)
}
}
Your nav-bar-component inject in constructor the loginService -make it public-
constructor(public loginService:LoginService){}
And your .html can be simple
<button [disabled]="!(loginService.isLoggin|async)">I'm login</button>
(*)tap not change the response, but executed when "someone" subscribe to our observable.
Here 'this.allowSearch' is getting initialized in buttonEnable(). Once you login to the application, You should call the 'buttonEnable()' method.
Same wise, When ever you logout from app, you should invoke the 'buttonEnable()' method.
So 'allowSearch' value will be updated.
Instead of this approach, you should have RXJS observables. have 'allowSearch' property in RXJS store and update based on login and logout actions.
Your component should subscribe for 'allowSearch' from store and update the 'allowSearch' component property.

components interaction 2 way angular

I have 2 components - one for a list of items and one for several buttons like save,cancel,summary etc.
In my buttons component I am using inputs and outputs to call the methods I need.
<button type="button" class="btn btn-danger ml-3" (click)="submit(true)" *ngIf="allowUserToFinalize(false)">
Submit
</button>
<button type="button" class="btn btn-danger ml-3" (click)="submit(false)" *ngIf="allowUserToFinalize(true)">
Cancel
</button>
allowUserToFinalize(false) -> this method is on items component and I have to send a parameter to it and use the returned value.
I have tried to do that with Output and Input - I emit an event with the param value to the item component, call the allowUserToFinalize(param) and then the result is send via Input to the button component and it is used in the ngIf directive.
This is working only on init, it sends event=undefined, it returns true and then it is not triggered anymore.
Is there another method to do this interaction?
items html
<app-items-action-buttons>
(allowUserToFinalize)="allowUserToFinalize($event)"
[allowUserToFinalize]="allowUserToFinalize()">
</app-items-action-buttons>
items ts
allowUserToFinalize(submit: boolean) {
if (submit) {
return false;
} else {
return true;
}
}
butons ts
#Output() allowUserToFinalizeEvent: EventEmitter<any> = new EventEmitter();
#Input() allowUserToFinalizeInput;
allowUserToFinalize(submit: boolea) {
this.allowMerchantToFinalizeDealEvent.emit(submit)
}
buttons html
<button type="button" class="btn btn-danger ml-3" (click)="submit(false)" *ngIf="allowUserToFinalizeInput">
Cancel
</button>
That is quite a complicated data flow. Lemme try to propose a simpler one:
<button type="button" class="btn btn-danger ml-3" (click)="submit(true)" *ngIf="showSubmit">
Submit
</button>
<button type="button" class="btn btn-danger ml-3" (click)="submit(false)" *ngIf="showCancel">
Cancel
</button>
<app-items-action-buttons>
[showSubmit]="allowUserToFinalize(true)"
(showCancel)="allowUserToFinalize(false)"
>
</app-items-action-buttons>
And if you still want to keep the data flow you wanted to use originally. This way you need to pass the callback (think of callback hell right away) as in input property:
#Input() allowUserToFinalizeInput: (isSubmit:bool) => bool;
and use it right the way you use it now. there is no event here and no need for #Output property

Store value of span or textarea in angularjs view

I have a call to a controller in my ASP.NET WebForms page:
input type="button" data-ng-click="addReply(post.PostId, LoggedInDisplayName, post.NewReply)" value="Submit" id="createReply" class="btn btn-default pull-right"
LoggedInDisplayName is a variable I need to pass to the addReply method, which does a RESTful API HTTP call in the service.
Unfortunately LoggedInDisplayName is a field that can only be sourced by ASP, as this is the login name of the current user, and I'm using Microsoft's built-in membership profile routines.
I can place the login name into a hidden span or textarea element using this logic in my code-behind C# file:
if (Membership.GetUser() != null)
{
loggedInDisplayName.InnerText = Membership.GetUser().ToString();
}
where loggedInDisplayName is the ID of the span or textarea.
But, how can I get the contents of the span or textarea into the LoggedInDisplayName field? I tried using ng-model, but this doesn't work - the span/textarea is reverted to a blank field.
Any assistance would be much appreciated.
just put in your submit button, ng-init="loggedInDisplayName = (asp variable)". This will initialize the variable to your asp variable.
To solve this problem, I loaded the asp variable into the DOM as follows
span style="visibility:hidden" id="loggedInDisplayName" ><%: LoggedInDisplayName() %>
And in the .cs code behind file:
public string LoggedInDisplayName()
{
string loggedInDisplayName = "";
// set the login name for use in creating new posts and replies
if (Membership.GetUser() != null)
{
loggedInDisplayName = Membership.GetUser().ToString();
}
return loggedInDisplayName;
}
Then a controller to create the variable in the scope
// The Global Variable defined outside angular
var loggedInDisplayName = $('#loggedInDisplayName').text();
//Define Controller
gwApp.controller('LoginName', ['$scope', '$window',
function ($scope, $window) {
$scope.LoggedInDisplayName = $window.loggedInDisplayName;
}
]);
I wrapped my existing controller in the new controller:
div id="loginName" data-ng-controller="LoginName">
... existing code ...
/div>
Then my Submit button:
input type="button" data-ng-click="addReply(post.PostId, LoggedInDisplayName, post.NewReply)" value="Submit" id="createReply{{ post.PostId }}" class="btn btn-default pull-right" />