Angular: Enable button asynchronously - html

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.

Related

Changing values of a counter variable in Angular

I have 2 buttons on my login page, Button1 and Button2. Both the buttons direct to the same URL page. But on clicking Button 2, I want to disable the functionality of Button 3 which is on the next URL page.
Button 3 should be accessed only when Button 1 was clicked on the main page.
Here's the HTML code of the main page. Button 1 is a part of the ngForm.
<button class="btn btn-primary" id="alert" type="submit">Login</button>
<button class="btn-primary" routerLink="/login/olduser" id="logins">Patient Login</button>
Here's the HTML code of Second page.
<button class="btn btn-primary" style ='margin-left: 700px;'routerLink="../../login/newuser">Register a new patient </button>
One possible solution I thought of was exporting a counter variable from the main page to the second page on clicking Button 2, which will inform to disable Button 3, but I failed to do so.
How can I implement this functionality?
Here's what I have tried till now :
<button class="btn-primary" (Click)="newUser()" id="logins">Patient Login</button>
public newUser(){
var status="success";
console.log(status);
this.router.navigateByUrl('/login/olduser');
}
I'm trying to print the value of "status" on console, to check if the method is being accessed but there's no output on console and also the url doesn't change.
I want to call this "status" variable in olduser.ts script.
It seems you're trying to limit the functionality of some sort of dashboard depending on user type (patient, non-patient).
I don't think you should rely on a referrer button at all here.
I'd send something like a list of permissions for user to client app after logging in and wrap it in a AuthorizationService of some kind. Then I'd check if the user has the permission to register a new patient and show/hide the corresponding button.
Of course, you shouldn't forget about server-side validation for registration requests.
UPD: if one of the user types doesn't distinguish between users and doesn't require server-side authentication, you can just generate some kind of default set of permissions in the service for those non-privileged users and keep the display logic for page 2 based on permission checks.
On Click of button pass a query parameter. Then on the next page read the value of the query parameter from URL and disable the button 3 based on the value.
Working Demo
Homepage HTML
<a routerLink='/page1' [queryParams]="{button: 'a'}"><button>button 1</button></a>
<a routerLink='/page1' [queryParams]="{button: 'b'}"><button>button 2 </button></a>
<router-outlet></router-outlet>
In the routed component .TS
import { Component, Input, OnInit } from "#angular/core";
import { ActivatedRoute } from "#angular/router";
#Component({
selector: "hello",
template: `
<h1>Hello {{ name }}!</h1>
<button [disabled]="isDisable">button3</button>
`,
styles: [
`
h1 {
font-family: Lato;
}
`
]
})
export class HelloComponent implements OnInit {
#Input() name: string;
isDisable: boolean;
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
this.isDisable = params.button === "a";
});
}
}
You can send the state of the button as a query parameter on button 2 click. Now, On the new page get the query params value and then apply property binding.
On Button 2 click :
this.router.navigate(['/newpage'], { queryParams: { state: "false"});
Now, on new page add as below :
import { ActivatedRoute } from '#angular/router'
export class newPage implements OnInit {
btnState
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.queryParams
.filter(params => params.state)
.subscribe(params => {
this.btnState = params
});
}
Now,apply property binding to the button
<button [disabled]="btnState">Button3</button>
There is multiple ways to achieve what you try to do:
With the click on Button 2, you can store in a service, a variable isActive to false and in your next url/Component, check from the service the variable to disabled or not your Button 3.
Navigate to your url with a params: my-new-url?ACTIVE=false, and in your new url/component, check the url to find the Params and disable your button according to the value

How do you add a value to datepicker from an Angular Factory?

i have an Angular Factory that gets a single date from the backend of my spring application, and i wanted to add it to an Input so the calendar input is always set with the date obtained from the backend, without the possibility for the user to change it. How could i achieve this? Should i put it on my controller or directly on the button? This is my code:
Factory(concatenated with other .factory):
.factory('DataInizioGeneraCalendario', function ($resource) {
return $resource('rest/anagrafica/dataInizioGeneraCalendario', {
get: {
method: 'GET'
}
});
Controller Function:
$scope.generaCalendario = function () {
$scope.modificaCalendarioDiv = true;
$scope.successMessage = false;
$("#idModificaCalendarioDiv").hide();
$scope.element = new Calendario();
autoScroll('generaCalendario');
$("#idErrorTemplate").hide();
$('#data').attr('disabled', false);
$("#idGeneraCalendarioDiv").show();
};
Input :
<div class="col-xs-12 col-md-2" >
<label for="dataInizio" class="row col-xs-12 control-label" style="text-align: left">da Data</label>
<input class="datepicker form-control" placeholder="gg/mm/aaaa" required type="text" id="data" ng-disabled="true" />
</div>
Edit : forgot to add, the controller function is called by the button that displays the input for the calendar.
Because your factory's GET request will return the date value asynchronously, it's better to have a $scope.date in your controller that will hold the date value that is returned from the server. Also, depending on the format in which you store dates on the backend, you might need to transform the value that is returned from the backend into the string format, so it would be properly consumed by the <input type="date"> as per Angular docs.
In your code, you need to bind the input element to this value, like this: <input ng-model="date">.
What it will do is bind this input to the data model, so that every time when user edits the input the $scope.date would be updated too.
If you do not want users to be able to edit this date, then you need to:
Keep the input field disabled <input disabled> (no need to use ng-disabled here, because you want to keep it always disabled). And also remove this line: $('#data').attr('disabled', false); in your function.
You the one-way binding, instead of two0way binding, like this: <input disabled ng-value="date">
Here is the working DEMO that shows two inputs: one that is editable and another that is not.

How can I change component without changing URL in Angular?

I would like to change component without changing URL. Let's assume that I have a component register. When I open my website I have url www.myweb.com. Then I would like to register by clicking sign up. I would like to display my component register without changing URL. Should I use ngIf or something else? Can you show me example how it should be done?
UPDATE I am sorry, but it seems to me that I was misunderstood. I tried
this solution:
login.component.ts:
showSignUp: boolean = false;
login.component.html:
<button (click)="showSignUp = true">Sign Up</button>
<register *ngIf="showSignUp"></register>
However when I clicking the button Log in I get this:
before:
after clicking:
After clicking the button Log in I would like to get a new website but with the same URL like this:
UPDATE
What do you think about solution shown below? In html file I will be checking whether variable authenticated is equal true. If so then I will display home component.
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
this.authenticated = true;
// this.router.navigate([this.returnUrl]);
},
error => {
this.authenticated = false;
this.alertService.error(error);
this.loading = false;
});
}
UPDATE
Unfortunately it doesn't work. Any ideas how can I use it with this button?
<button [disabled]="loading" class="btn btn-primary">Log in</button>
You can use *ngIf and show the component in condition!
examle
In your sign up component, set a variable and change its value on click of sign up button. And display your register component on click of the login by pitting the condition in display
// sign up component
showRegister = false;
in your sign up component html
<register *ngIf="showRegister"></register>
Yes, this is a perfect use case for ngIf. Try not to over engineer it.
ngIf is the way to go on this kind of thing.
Just put in your component code something like
showSignUp: boolean = false;
then in template:
<button (click)="showSignUp = true">Sign Up</button>
<register *ngIf="showSignUp"></register>
And since you seem new to Angular, I'll mention that in order to use ngIf in template, your module needs to import the CommonModule like
import { CommonModule } from '#angular/common';
imports: [
CommonModule,
]

How do i get input form value without submitting it?

I want the input value from user without submitting any thing then i want to pass it through ajax method as parameter to action method. I tried many method but i could not found a solution.
Here is the code
<input type="text" id="task" name="task" value="" />
#Ajax.ActionLink("ADD TASK", "show_task",new {task=Request["task"]}, new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "print",
InsertionMode = InsertionMode.Replace
})
Here is the controller action method
public ActionResult show_task(string task)
{
var add_task = new tasks_table();
add_task.task = task;
add_task.id = 24;
add_task.f_id=10;
add_task.date_oftask=DateTime.Now;
db.tasks_table.Add(add_task);
db.SaveChanges();
var tasks = db.tasks_table.Include(t => t.user_detail);
return PartialView("render_tasks",tasks);
}
Since you want the current value of the textbox, you may better do it yourself with your own javascript code to make the ajax call, instead of relying on the Ajax.ActionLink helper method.
So change your Ajax.ActionLink call to a normal action link.
<input type="text" id="task" name="task" value="" />
#Html.ActionLink("Add Task","show_task", null, new {id="addTask"})
<div id="print"></div>
Now listen to the click event on this link, read the value of the text box and send that to your server. You may use jQuery $.post method to do so. In the response callback, you can update the print div's content with the response coming back from your server.
$(function(){
$("a#addTask").click(function(e){
e.preventDefault();
$.post($(this).attr("href"), { task:$("#task").val()},function(res){
$("#print").html(res);
});
});
});
You can use JavaScript focusOut function to send the value to controller.
by focusOut method, we get the value in input field instantly when we moved to next field.
$('#task').focusOut(function(){
Your ajax call method....
});
Hopes it helps.

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" />