stimulus controller in Rails 6 app not updating - ruby-on-rails-6

Working through a tutorial and I am missing something. There is a stimulus controller that is being developed to show/hide some content. The first task was just to console.log out the word "Click!" to the console.
Now I have updated the controller to handle the show/hide behavior however the only thing that is happening is that is keeps console.logging out 'Click!'
I searched my app and found some files in the .cache in node_modules that had that code still in it so I removed that, it still appears now even though there is no reference to 'Click!' in the code at all.
Webpack is compiling without error (and has compiled many times asI have tried to debug this).
You can even see that the referenced line no longer matches
The controller is
import { Controller } from "stimulus"
export default class FavoriteToggleController extends Controller {
static targets = ["elementToHide","elementWithText"] // Stimulus requires that any targets in use from the controller need to be declared in a static variable called 'targets'
static values = { visible: Boolean }
elementToHideTarget: HTMLElement // typescript visible declaration of the property
elementWithTextTarget: HTMLElement
visibleValue: Boolean
connect(): void {
this.updateHiddenClass()
this.updateText()
}
toggle(): void {
this.flipState()
this.updateHiddenClass()
this.updateText()
}
// functions
flipState(): void {
this.visibleValue = !this.visibleValue
}
visibleValueChanged(): void {
this.updateHiddenClass()
this.updateText()
}
updateHiddenClass(): void {
this.elementToHideTarget.classList.toggle("hidden", !this.visibleValue)
}
newText(): string {
return this.visibleValue ? "Hide" : "show"
}
updateText(): void {
this.elementWithTextTarget.innerText = this.newText()
}
}
View
<%= turbo_frame_tag("favorite-concerts") do %>
<section class="my-4" data-controller="favorite-toggle" data-favorite-toggle-visible-value="true">
<div class="text-3xl font-bold">
Favorite Concerts
<button class="<%= SimpleForm.button_class %> py-1 text-xl font-semibold" data-action="favorite-toggle#toggle">
Hide
</button>
</div>
<div data-favorites-tottle-target="elementToHide">
<div class="text-xl font-bold" id="no-favorites">
<% if current_user.favorites.empty? %>
No favorite concerts yet
<% end %>
</div>
<div id="favorite-concerts-list">
<% current_user.favorites.each do |favorite| %>
<%= render(favorite) %>
<% end %>
</div>
</div>
</section>
<% end %>
Folder structure
There are no errors in the console at all, just this old code that keeps executing.
I have done a hard refresh, restarted everything, nothing makes this go away.

Related

Kentico 9 shopping cart ECommerceContext amounts insconsistent between macro and layout/.NET

I have a Kentico 9 ecommerce site. On one of the pages in the checkout process, I have a static HTML web part. Its Content field contains:
<ul class="cart-total-list text-center mb0">
<li style="text-align: left;"><span>Products</span><span>{% FormatPrice(ECommerceContext.CurrentShoppingCart.TotalItemsPrice - ECommerceContext.CurrentShoppingCart.TotalItemsTax) #%}</span></li>
<li style="text-align: left;"><span>Tax</span><span>{% FormatPrice(ECommerceContext.CurrentShoppingCart.TotalTax) #%}</span></li>
<li style="text-align: left;"><span>Shipping</span><span>{% FormatPrice(ECommerceContext.CurrentShoppingCart.Shipping) #%}%}</span></li>
<li style="text-align: left;"><span>Shipping Tax</span><span>{% FormatPrice( ECommerceContext.CurrentShoppingCart.TotalShipping - ECommerceContext.CurrentShoppingCart.Shipping) #%}</span></li>
<li style="text-align: left;"><span>Total</span><span>{% FormatPrice(ECommerceContext.CurrentShoppingCart.TotalPrice) #%}</span></li>
</ul>
which, for example, produces the following output:
Products $58.30
Tax $4.30
Shipping $0
Shipping Tax $16.19
Total $74.49
This is incorrect. Products total should be $54 (Somehow $4.30 tax is included.)
Shipping should be $15.
Shipping tax should be $1.19. (Because shipping is zero, the full amount is displayed.)
Also, sometimes the Tax displays zero but is included in the amount in my Products line.
Now if I instead render these values using C# in the web part's layout as follows:
<%# Control Language="C#" AutoEventWireup="true" Inherits="CMSWebParts_Text_staticHTML" Codebehind="~/CMSWebParts/Text/staticHTML.ascx.cs" %>
<%
var cart = CMS.Ecommerce.ECommerceContext.CurrentShoppingCart;
%>
<asp:Literal ID="ltlText" runat="server" EnableViewState="false" />
<ul class="cart-total-list text-center mb0">
<li style="text-align: left;"><span>Products</span><span><% Response.Write(cart.GetFormattedPrice(cart.TotalItemsPrice - cart.TotalItemsTax,false)); %></span></li>
<li style="text-align: left;"><span>Tax</span><span><% Response.Write(cart.GetFormattedPrice(cart.TotalTax,false)); %></span></li>
<li style="text-align: left;"><span>Shipping</span><span><% Response.Write(cart.GetFormattedPrice(cart.Shipping,false)); %></span></li>
<li style="text-align: left;"><span>Shipping Tax</span><span><% Response.Write(cart.GetFormattedPrice(cart-TotalShipping - cart.Shipping,false)); %></span></li>
<li style="text-align: left;"><span>Total</span><span><% Response.Write(cart.GetFormattedPrice(cart.TotalPrice,false)); %></span></li>
</ul>
I get the following values:
Products $54.00
Tax $4.30
Shipping $15.00
Shipping Tax $1.19
Total $74.49
These are exactly what I expected.
Why the differences? I can certainly stick with the latter approach, but I am concerned that something is broken and may have future side-effects.
UPDATE:
I went with a custom macro field instead of a custom macro method. I just added the following class to my old_app_code folder. (because I have a pre-compiled web application) It appears to work as desired.
using System;
using CMS.Base;
using CMS.MacroEngine;
using CMS.EventLog;
[MacroLoader]
public partial class CMSModuleLoader
{
/// <summary>
/// Attribute class for registering custom macro extensions.
/// </summary>
private class MacroLoaderAttribute : CMSLoaderAttribute
{
private const string EVENT_SOURCE = "MacroLoaderAttribute";
private const string EVENT_CODE = "EXCEPTION";
/// <summary>
/// Called automatically when the application starts.
/// </summary>
public override void Init()
{
MacroContext.GlobalResolver.SetNamedSourceDataCallback("CartShipping", CartShipping);
MacroContext.GlobalResolver.SetNamedSourceDataCallback("CartTotalItemsTax", CartTotalItemsTax);
}
private object CartShipping(EvaluationContext context)
{
double retVal = 0d;
try
{
retVal = CMS.Ecommerce.ECommerceContext.CurrentShoppingCart.Shipping;
}
catch (Exception ex)
{
EventLogProvider.LogException(EVENT_SOURCE, EVENT_CODE, ex);
}
return retVal;
}
public static object CartTotalItemsTax(EvaluationContext context)
{
double retVal = 0d;
try
{
retVal = CMS.Ecommerce.ECommerceContext.CurrentShoppingCart.TotalItemsTax;
}
catch (Exception ex)
{
EventLogProvider.LogException(EVENT_SOURCE, EVENT_CODE, ex);
}
return retVal;
}
}
}
Now CartShipping and CartTotalItemsTax are directly available for use in macro expressions.
Not all properties of CurrentShoppingCart item exist in K# macro object. For example, TotalItemsTax doesn't exist, so it returns 0 for this. The same with Shipping property. That's why you have difference there. All available properties you can see in System application -> Macros -> Console
I can confirm the TotalItemsTax and Shipping properties are not registered for macros in ShoppingCartInfo object, therefore the macro engine will return 0 for them. This leads to incorrect calculations in macros, while in standard ascx code it works.
Additional registration of the system object types properties for macros is not easily possible, so if you want to go with K# macros, I'd recommend to create a custom macro method (see https://docs.kentico.com/k9/macro-expressions/extending-the-macro-engine/registering-custom-macro-methods), where you would call the standard API in C# (e.g. properties of the ECommerceContext.CurrentShoppingCart) with all the properties available. You can even return the resulting value (subtraction of tax from total) directly instead of doing it in the markup or transformation.
Hope this helps...

Creating reusable HTML view components using Razor in ASP.NET MVC

I have a Razor helper function that creates a re-usable HTML panel that saves me writing the same HTML over and over again.
#helper DefaultPanel(string panelTitle) {
<div class="panel">
<div class="panel-logo"><img src="/logo.png"></div>
<div class=panel-inner">
<p class="panel-title">#panelTitle</p>
<div class="panel-content">
/* Can I pass content to be rendered in here here? */
</div>
</div>
</div>
</div>
}
I'm wondering, is it possible to re-use this helper to fill .panel-content with more HTML to allow further flexibility and code reuse - similar to something like below:
#LayoutHelpers.DefaultPanel("Welcome back") {
<div class="panel-content-inner">
<p>Welcome back, please select from the following options</p>
Profile
My Defails
</div>
}
Whilst using .NET MVC I've noticed the Html.BeginForm() does a similar thing when wrapping the code within the #using statement within the Html.BeginForm declaration, like so:
#using (Html.BeginForm("Index", "Login", FormMethod.Post))
{
<div>This content gets rendered within the <form></form> markup.</div>
}
But can this done using #helper methods? If not, is it possible to create a HtmlHelper extension to do a similar thing the way the Html.BeginForm() method does?
You can do a very similar thing using the #section syntax as seen here
This seems like something that would be really useful to be able to do, and odd that there's no easy way to do it on a component level.
There are two ways to achieve the required functionality.
1. #helper
Create #helper which accepts whatever parameters you need plus a function (single object parameter, returns object):
#helper DefaultPanel(string panelTitle, Func<object, object> content)
{
<div class="panel">
<div class="panel-logo">
<img src="/logo.png" />
</div>
<div class="panel-inner">
<p class="panel-title">#panelTitle</p>
<div class="panel-content">
#content(null)
</div>
</div>
</div>
}
Usage:
#DefaultPanel("title",
#<div class="panel-content-inner">
<p>Welcome back, please select from the following options</p>
Profile
My Defails
</div>
)
Your function may also accepts parameters, example here.
2. HtmlHelper extension method
Add the following code anywhere in your project:
namespace System.Web.Mvc
{
public static class HtmlHelperExtensions
{
public static HtmlDefaultPanel DefaultPanel(this HtmlHelper html, string title)
{
html.ViewContext.Writer.Write(
"<div class=\"panel\">" +
"<div class=\"panel-inner\">" +
"<p class=\"panel-title\">" + title + "</p>" +
"<div class=\"panel-content\">"
);
return new HtmlDefaultPanel(html.ViewContext);
}
}
public class HtmlDefaultPanel : IDisposable
{
private readonly ViewContext _viewContext;
public HtmlDefaultPanel(ViewContext viewContext)
{
_viewContext = viewContext;
}
public void Dispose()
{
_viewContext.Writer.Write(
"</div>" +
"</div>" +
"</div>"
);
}
}
}
Usage:
#using (Html.DefaultPanel("title2"))
{
<div class="panel-content-inner">
<p>Welcome back, please select from the following options</p>
Profile
My Defails
</div>
}
The extension method writes directly to the context. The trick is to return a disposable object, which Dispose method will be executed at the end of using block.
I don't know if #helper methods can do this but HtmlHelper extensions certainly can. You've mentioned the Html.BeginForm() example which is probably the most well known - all that does is return an object which implements IDisposable which means that when the Dispose() method is called it just calls the complimentary Html.EndForm() method to add the appropriate closing tags.
It would be very simple to do something similar for your HTML code. You can view the source code to the ASP.NET MVC HtmlHelpers at http://aspnetwebstack.codeplex.com/ - the BeginForm() code can be specifically be viewed here.

MVC3 #Model becomes null in layout

So I have something odd happening in a MVC3 layout I created. It's strongly typed to BaseVM. Every View model inherits from BaseVM. When I debug and step through the code and it it steps through my layout, the BaseVM model is not null and it calls a method to get the current year for the copyright in the footer. But as soon as I step to the bottom of the layout, it throws an exception back up where I was calling the property to get the year and suddenly the Model is null. Now this doesn't cause the application to show an error screen or message, but this exception gets logged every time the page is loaded. Here's a code sample:
public class BaseVM
{
public string CurrentYear
{
get
{
return DateTime.Today.Year.ToString();
}
}
public BaseVM()
{
}
}
public class PrelaunchReserveVM : BaseVM
{
public PrelaunchDTO Prelaunch { get; set; }
public PrelaunchReserveVM()
: this(new PrelaunchDTO()) { }
public PrelaunchReserveVM(PrelaunchDTO prelaunch)
: base()
{
this.Prelaunch = prelaunch;
}
}
The action in the controller:
public ActionResult Reserve()
{
return View("Reserve", new PrelaunchReserveVM(new PrelaunchDTO()));
}
The layout:
#model StickyThink.Models.VM.BaseVM
...
<div id="container">
<div id="main" role="main" style="padding: 0px; margin: 0px;">
#RenderBody()
</div>
</div>
<footer>
<div id="FooterPageContainer" class="center">
Copyright &copy #Model.CurrentYear ... All rights reserved.
</div>
</footer>
<!-- END: Add your site or application content here -->
#Html.Partial("_Scripts")
#RenderSection("scripts", false);
So it steps into #Model.CurrentYear and model is not null. Then it steps down to #RenderSection (to render some scripts from the view) and then an exception is thrown and #Model is null. Thoughts?
You need to pass Model as the 2nd parameter in #Html.Partial("_Scripts", Model).
If I had to take a wild guess, I think there is a problem with the content of the _Scripts partial. Maybe it needs the model #krillgar, but my guess onn that would be no. I would suggest moving the _Scripts partial to NOT be a partial and reference the scripts in the header like normal. I suspect that this exception will then shows its face earlier and help you find the problem, and the reason the Model becomes null is becuase of the type of exception. So if you move the _Scripts partial and have null earlier, you know this is the place to look.

Acknowledge and Reload PartialView with Razor

I am new to MVC3 and Razor.
I have an "attention banner" on the master page as a Partial View that I want to "acknowledge" with a click on a link to close the banner (without reloading the page). I believe I need to use jQuery and an Ajax call, but I just can't seem to find the right combination.
Here is part of my _Layout.cshtml:
<section id="main">
<span id="attentionBar">#{ Html.RenderPartial("_AttentionBarPartial"); }</span>
#RenderBody()
</section>
This is my Partial View (just using Session as a shortcut for now to get it to work). I'm not sure what to use as the "link" to reload the view:
#{ this.Layout = null;}
#if(! String.IsNullOrWhiteSpace(#Session["Attention"].ToString()))
{
<div class="attentionPanel">
<span class="attentionLabel">Attention</span>
#Session["Attention"].ToString()
<span class="attentionLabel">
#* WHAT DO I PUT HERE *#
#Ajax.ActionLink("X", "AcknowledgeAttentionBar", "Home", new AjaxOptions{ UpdateTargetId="attentionPanel", InsertionMode=InsertionMode.Replace })
</span>
</div>
}
Here is my Home controller. Again, I am not sure that the code is quite correct, but essentially I will clear out the condition that shows the attention banner.
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Home Controller Updated At " + DateTime.Now.ToLongDateString()
+ " " + DateTime.Now.ToLongTimeString();
return View();
}
public PartialViewResult AcknowledgeAttentionBar()
{
Session["Attention"] = String.Empty;
return PartialView("_AttentionBarPartial");
}
}
2 things:
Make sure you have included the jquery.unobtrusive-ajax.js script to your page in order for Ajax.ActionLink helper to work and send an AJAX request when the link is clicked instead of a normal redirect:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
In your AjaxOptions you have specified UpdateTargetId="attentionPanel" but there's no element in your markup with id="attentionPanel". You have a div with class="attentionPanel" but that's not the same thing. On the other hand you have wrapped your banner in a <span id="attentionBar">, so you probably meant UpdateTargetId="attentionBar".

Problem using RenderAction() with the current action

I'm building an ASP.Net MVC 2 application with a component architecture. There are two different types of components: Elementary Components, which have an associated controller action rendering a partial view, and Layout Components, which render all their child components (Elementary Components or again Layouts) in a certain layout.
Here is my generic RenderComponent() action method, which takes a component ID and renders the appropriate view:
[ChildActionOnly]
public ActionResult RenderComponent(int id)
{
ComponentRepository repository = new ComponentRepository();
Component component = repository.GetComponent(id);
if (component.ControllerName != null && component.ViewName != null)
{
// render elementary component
return PartialView("Elementary", component);
}
else
{
// render layout
return PartialView(component.Layout.ViewName, component);
}
}
Elementary.ascx renders an elementary component:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyApp.Models.Component>" %>
<% Html.RenderAction(Model.ViewName, Model.ControllerName); %>
Currently the only existing layout is the VerticalLayout.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyApp.Models.Component>" %>
<%
foreach (var child in Model.ChildComponents()) {
%>
<div class="layout-container">
<% Html.RenderAction("RenderComponent", "Core", child.ID); %>
</div>
<%
}
%>
The Problem:
When I tried to render an example layout component with three associated elementary child components, the page wouldn't render. Some debugging revealed the following problem:
RenderComponent(5) renders the layout view.
For rendering the first child component in the layout, Html.RenderAction("RenderComponent", "Core", 1) is called in the view. Stepping further, I discovered that in effect RenderComponent(5) is called instead of RenderComponent(1)!!
This obviously results in an infinite loop of the layout view rendering itself.
Why is this happening? How can I fix it? Is my hierarchical component architecture incompatible with ASP.Net MVC? How would you build such a system in ASP.Net MVC?
OK, my bad... Of course it has to be <% Html.RenderAction("RenderComponent", "Core", new { id = child.ID}); %> in VerticalLayout.ascx.

Resources