click twice on button process the ngIf statement in other component - javascript

I've added breadcrumb in my site such that when clicks on it, it makes that specific variable undefined(which session stored value and can retrieved easily in other component) and based on that, in other component I've ngIf for that variable such that if that variable is undefined then that specific div should not be shown and other div should be shown. You can get more idea by looking into following gifs.
Problem I'm facing is on first click it don't go back to that other div which it does on second click.
Clicking twice on breadcrumb for Model(or its value) do the trick but i want to do this happens on first click.
Breadcrumb component TS file:
#SessionStorage() model: any;
onClickModel(m){
this.model = m.value; // gets the value from button and set as model value
}
other component HTML file:
<div class="model" *ngIf="model && !provider">
<div class="row">
<div class="col-md-12 text-center pb-20">
<h2>Choose your Carrier</h2>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<!-- That next component buttons for providers -->
</div>
</div>

Related

get details of card by clicking on that card - vue js

I have a cardview. There are multiple cards. I want details of a card while clicking on that particular card. How can i do that i am not sure?
<div class="container">
<vu-page-card
v-for="page in pageList"
:key="page.id"
:pageId="page.pageId"
:pageItem="page.pageItem"
:pageType="page.type"
class="item"
#onHomeRefresh="onHomeRefresh"
/>
</div>
How to modify or add code to get this functionality? Any simple example is also applicable
I'm not sure of the exact use case. But with what I can see from the code you've given, you could simply attach a click handler to the component and pass the card details as params.
<div class="container">
<vu-page-card
v-for="page in pageList"
:key="page.id"
:pageId="page.pageId"
:pageItem="page.pageItem"
:pageType="page.type"
class="item"
#click="onCardClick(page)" 👈
#onHomeRefresh="onHomeRefresh"
/>
</div>

How to use multiple instances of the same View Component and Javascript files in the same Razor Page?

I have a razor page where I'm importing two or more view components of the same type/source into a razor page. The view component is essentially the same but each instance will load different values from the database depending on the drop selections on the form instance as well streaming events from a different source through SignalR
Because each view component essentially points to the same javascript file, I find that only the first loaded instance of this view component is operational.
I'm not sure how to configure razor so it sees each loaded view component as a separate instance, so I can treat each razor form in the view component as a separate instance. this issue will likely also affect the fact that I have a textarea that will be dynamically be updated by SignalR
<div class="container-fluid h-100 p-0 m-0">
<div class="row justify-content-center h-100 pl-0">
#Html.AntiForgeryToken()
<div class="col-12 col-sm-12 col-md-6">
#await Component.InvokeAsync("EventsMonitor")
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
</div>
<div class="col-12 col-sm-12 col-md-6 pl-sm-3 pl-md-2 pt-3 pt-sm-3 pt-md-0">
#await Component.InvokeAsync("EventsMonitor")
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
</div>
</div>
OK so this is how I worked it out:
First things first, we don't want to be loading the reference JavaScript file more than once per razor page, I believe the browser has some intelligence on this point but to tidy up the code in my original question, lets move the script down to underneath the razor code block:
Razor Page (that will show multiple instances of the same view component)
#model MyProject.Pages.EventsMonitor.ViewEventsModel
#{
}
<div class="container-fluid h-100 p-0 m-0">
<div class="row justify-content-center h-100 pl-0">
#Html.AntiForgeryToken()
<div class="col-12 col-sm-12 col-md-6">
#await Component.InvokeAsync("EventsMonitor")
</div>
<div class="col-12 col-sm-12 col-md-6 pl-sm-3 pl-md-2 pt-3 pt-sm-3 pt-md-0">
#await Component.InvokeAsync("EventsMonitor")
</div>
</div>
</div>
<!-- By using 'defer' you are telling the parser not to execute
it until the document had loaded thus avoiding the problem
of the having to put it in the layout for proper execution.
Defer is supported by chrome, safari, and ie(10+), ff(3.6+), o(15+) -->
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
In the above, you'll see that we have referenced the
#model MyProject.Pages.EventsMonitor.ViewEventsModel
which is a new class I created for referencing an integer (Counter) that we will increment each time we load a new instance of the view component.
Next up we create a small public class:
namespace MyProject.Models.EventsMonitor
{
public class EventsMonitorViewModel
{
public int Counter { get; set; }
}
}
Now within the ViewComponent.cs file, we modify the method that returns the view:
namespace MyProject.ViewComponents
{
public class EventsMonitor : ViewComponent
{
[BindProperty] // Bind to the small class we created in previous step.
public EventsMonitorViewModel EventsMonitorViewModel { get; set; }
private static int _value = 0;
public IViewComponentResult Invoke()
{
var EventsMonitorViewModel = new EventsMonitorViewModel
{
// See MS Link in notes for an increment function.
Counter = Interlocked.Increment(ref _value)
};
return View(EventsMonitorViewModel);
}
}
}
The MS Guidance for incrementing is here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked.increment?view=net-5.0
So in essence, each time we load a new instance of the same View Component, the Razor View is returned with the view model class that we bind to the razor page.
In my View Component Razor file (Default.cshtml file) we modify the Id's of each razor/html component that we will be interacting with using JavaScript. I'm not going to include the whole file, but a sample section of the razor form is shown below (these dropdown select boxes you can see in the image I showed in my original question):
#model WebApp_PLUGIN.Models.EventsMonitor.EventsMonitorViewModel
<div class="form-group" style="margin-top: 1.5em">
<div class="row">
<div class="col-sm">
<label class="control-label">Plugin Type</label>
<select class="form-control" id="#("pluginTypeSelect"+Model.Counter)" onchange="pluginTypeSelect(this.id)">
<option value="">Select</option>
<option value="RS232Port">RS232 Port</option>
<option value="SmtpServer">SMTP Server</option>
<option value="TcpClient">TCP Client</option>
<option value="TcpServer">TCP Server</option>
</select>
</div>
<div class="col-sm mt-sm-0 mt-3">
<label class="control-label">Source</label>
<select class="form-control" id="#("pluginSourceSelect"+Model.Counter)">
<option value="">Select</option>
</select>
</div>
</div>
<div class="text-danger" id="#("eventsMonitorMessageBarTop"+Model.Counter)" style="white-space: pre-line"></div>
</div>
</div>
In the above Razor code block, for each element Id, we add the counter variable to end of the Id string so as each instance of the View Component is loaded, each element will have a unique Id that increment upwards by +1.
So the result from all the above is when using JavaScript functions for logic of the UI components in razor, each view component and associated form elements will have a unique Id.
Sample JavaScript code below for testing:
function pluginTypeSelect(clicked_id) {
// Each dropown select from each instance of the View Component will have a unique Id
alert(clicked_id)
}
In my testing, with reference to the screenshot in my original question, the dropdown select on the LHS View Component produced and Id "pluginTypeSelect1" and the RHS View Component produced and Id "pluginTypeSelect2"
The only part i hadn't addressed yet is the fact that the "Counter" variable will keep incrementing by +1 each time the Razor page is loaded, this isnt such an issue for me, but perhaps a very long running app it would be better to reset the integer back to zero again at some point so you don't end up with a long int. I'll think up a solution for this then update my answer.
Hopefully this helps others who come up against a similar conundrum...

A component is not receiving any of it's #Input values

I use Angular 8 and I have 3 components:
CalculationFirst : app-calculation-first
CalculationSecond : app-calculation-second
CalculationThird : app-calculation-third
CalculationFirst is the "parent" component and has CalculationSecond as a "child" in a way that I use CalculationSecond inside html template of CalculationFirst.
So in CalculationFirst.component.html it looks like this:
<div class="container">
<form #f="ngForm" (ngSubmit)="submit()" novalidate *ngIf="settings.isloaded == true">
<div class="row">
<app-calculation-second [elements]="settings.seconds.elements" [epics]="epics"[types]="types" (opendialoglistevent)="openDialogList($event)"></app-calculation-second>
</div>
</form>
</div>
Then CalculationSecond.component.html looks like this:
<div class="col-lg-2 box">
<div class="row">
<div class="row content" *ngFor="let element of elements;">
<div class="col-lg-14">
<app-calculation-third [elem]="element" [types]="types"></app-calculation-third>
</div>
</div>
</div>
</div>
And finally CalculationThird.component.html looks like :
<div class="col-lg-14">
TEST_TEXT_1
{{elem}}
TEST_TEXT_2
</div>
Now, the problem is if I were to just look at my rendered page, only TEST_TEXT_1 page shows, {{elem}} does not render and neither does TEST_TEXT_2. If I am to check the value of elem, it is undefined. I would expect to get an error that I am trying to display undefined, however I do not get anything. My environment.ts is not set to production, so I do not know if my error is not big enough for angular to inform me. (On a tangent, I don't even get an error if I use a json object in an *ngFor instead of an enumerable (Array), but I'm still not sure if I have some lacking setting).
I have also tried, when I use the third component, to not pass the element from *ngFor but to pass a handmade object {'elemId':0}, this had the same result.
If I move :
<app-calculation-third [elem]="element" [types]="types"></app-calculation-third>
to CalculationFirst, making it a direct child, it works perfectly fine, regardless of what I put in there. Is there a limit to the amount of child components you can have? Am I missing something?
*Edit: Also for those who suggested it is the *ngFor or the usage of different variables, I can make CalculationSecond look like the following and still it doesn't work:
<div class="col-lg-2 box">
<div class="row">
<div class="row content" *ngFor="let element of elements;">
<div class="col-lg-14">
</div>
</div>
</div>
<app-calculation-third [elem]="{ elementId: '' }" [types]="types"></app-calculation-third>
</div>
You are passing the elements to seconds input.
[seconds]="settings.seconds.elements"
But you use elements in your app-second-calculation element.

change page layout on link click vue.js

I'm learning how to use vue.js
I've a shared hosting plan where I can only use html. I'm fetching the data I need using axios and a remote wordpress installation that will act as a backend only. What I need to know, is how I can change the DOM content of the index.html using vue if the user click on a link and I need to change the layout of the page because a different presentation for the contents is needed?
See the example:
<div id="vue-app">
link to layout 2
<div class="col-12">starting layout </div>
</div>
// after the user click the link (v-on:click) the layout change
<div id="vue-app">
link to layout 1
// layout change
<div class="col-6">new layout </div>
<div class="col-6">new layout </div>
</div>
Please read up on Conditional Rendering in Vue.js.
You can have a boolean variable in the data compartment of your script tag and change it on click.
And in the tags put v-if="your_bool_variable".
<div id="vue-app" v-if="layout_switch">
link to layout 2
<div class="col-12">starting layout </div>
</div>
// after the user click the link (v-on:click) the layout change
<div id="vue-app" v-else>
link to layout 1
// layout change
<div class="col-6">new layout </div>
<div class="col-6">new layout </div>
</div>
Negate the boolean variable at the #click event.
Data could look like the following:
<script>
export default {
name: "YourComponent",
data: () => {
return {
layout_switch: true
}
},
methods: {
changeLayout() {
this.layout_switch = !this.layout_switch;
}
}
}
</script>

Passing models in AngularJS

I am building my first AngularJS app comming from backbone. I have a list where the user can select an item. The goal is show the details of the selected item in a view below the list. The list-view and detail-view are both part of the main-view.
my list view
<div id="rfc-records" class="container-fluid">
<div ng-repeat="record in records" ng-click="selectRow()" class="row select table-row">
<div class="col-lg-1 center">
{{record.id}}
</div>
<div class="col-lg-1 center">
{{record.rfcObject}}
</div>
<div class="col-lg-5">
{{record.rfcFunction}}
</div>
<div class="col-lg-2">
{{record.status}}
</div>
<div class="col-lg-3">
{{mii.utils.date.extToIntDate(record.firstProcessing)}}
</div>
</div>
</div>
As you see I already added an event to each row: ng-click="selectRow()".
It is unclear to me how to know the selected row in this function. I could do something like this :
ng-click="selectRow(record)
MainController
$scope.selectRow = function(record){
alert(record.id); // undefined
}
The result is undefined so this does not work. Plus this seems like a bad approach to pass the model back from the view to the controller. I might be able to get the application working but I have the feeling that I won't be using the paradigm as intended.
In backbone I would have a seperate view for each row where the model is bound to. But in Angular models aren't as explicit as in backbone.
In general I don't really understand how models work in Angular. R
Regarding this example I have the following questions:
How do I know what item is selected in the list
Where should I put the selectRow function? In the controller of the Mainview or in the list-view directive?
How do I pass the selected model to the details-view.
Well, passing current item into ngClick handler is pretty usual way to solve this task. I'm not sure why it's not working for you, it should. Here is the example of this typical approach.
In backbone I would have a seperate view for each row where the model is bound to. But in Angular models aren't as explicit as in backbone.
Actually Angular is even more elegant in this concern. You still have model available in every iterated row. You can refer current child scope as this in controller. So in your case if you don't want to pass record object into controller function on click, you can use this and it will point to the current scope object (remember that ngRepeat creates new child scope for every row):
$scope.selectRow = function() {
alert(this.record.id);
};
and you don't have to pass anything in HTML:
ng-click="selectRow()"
Demo: http://plnkr.co/edit/kN0vB6N6v7XnqASRSmAd?p=preview
ng-click and ng-repeat are in same div. You can add a new div in this repeated div like and this is works for me :
<div id="rfc-records" class="container-fluid">
<div ng-repeat="record in records" class="row select table-row">
<div class="col-lg-1 center">
Select This item<input type=button ng-click="selectRow(record)">
</div>
<div class="col-lg-1 center">
{{record.id}}
</div>
<div class="col-lg-1 center">
{{record.rfcObject}}
</div>
<div class="col-lg-5">
{{record.rfcFunction}}
</div>
<div class="col-lg-2">
{{record.status}}
</div>
<div class="col-lg-3">
{{mii.utils.date.extToIntDate(record.firstProcessing)}}
</div>
</div>
</div>

Categories

Resources