Razor Pages - Is it possible to route to a View Component for AJAX refresh - asp.net-core

Context:
I have a section of a view that I want to update on a regular interval via JS.
What I have done so far:
Using the information given in: Viewcomponent alternative for ajax refresh
created a view component that encapsulates the region that I want to refresh
attempted to create a custom route to a view component as follows
options.Conventions.AddPageRoute("/Components/ViewComponent/default", "FriendlyRouteAlias");
use the following script to attempt to load the (updated) view component and inject the value into a div:
<script>
var container = $(".DataToUpdate");
var refreshComponent = function () {
$.get("Route/to/view/component", function (data) { container.html(data); });
};
$(function () { window.setInterval(refreshComponent, 1000); });
</script>
Is it even possible to load a View Component this way or should I be looking at another way of accomplishing this?

As the commenters suggested, I was able to get it working by using an MVC controller action to return the view component directly. I will add that I used an MVC controller rather than an API controller because I was dealing with a view rather than data. (see Difference between ApiController and Controller in ASP.NET MVC)

Related

Vue.js 3 : Accessing a dynamically created component

I have a vue.js 3 application that needs to dynamically create components and access them.
The proper way to dynamically create them and injected them in the DOM seems to be th wrap them in an app using createApp, and this part works, when I call test() a new copy of the components appears at the bottom of the DOM.
Now I need to be able to get a reference to that component son I can call public (exposed) methods on it.
In my (actual) code below, what would allow me to get a reference to my component ?
import { createApp, h } from "vue";
import ConfirmModal from '#/views/components/ui/confirm-modal.vue';
function test()
{
let componentApp = createApp({
setup() {
return () => h(ConfirmModal, { title: "Fuck yeah!", type: "primary" });
}
});
const wrapper = document.createElement('div');
wrapper.setAttribute('id', 'confirm-modal-0');
componentApp.mount(wrapper);
document.body.appendChild(wrapper);
let _confirmModal: ConfirmModal = ???????????????????
_confirmModal.show();
}
EDIT : Here's my use-case: I have a helper function in a service which is used to confirm actions (like deletes) using a Modal dialog. This helper/service is pure TS, not a Vue component, but needs to instanciate the modal (which is a vue component), have it injected in the DOM and have its public methods callable (by my helper/service).
Right now, the only thing that works is to have a sungle copy of the modal component in my root layout and have to root layout foward the ref to my service, which can then use the component. But this isn't great because I need multiple instances of the dialog, and isn't good SOC to have to root layout handle a modal dialog.

Blazor dynamically createElement and appendChild

i want to dynamically create DIV Containers via JSInterop in Blazor Webassembly. My approach was to create a CreateElement method in C# which calls createElement in javascript and returns a ElementReference as a Result. But when i run the Following code, i just get an empty object.
C# code:
public object CreateElement(ElementReference elementReference)
{
return JsRuntime.Invoke<object>("createElement",
elementReference,
DotNetObjectReference.Create(this));
}
Javascript code:
createElement(element, objectReference) {
const newDiv = document.createElement("div");
return element.appendChild(newDiv);
}
You don't need JS for that. Blazor was made so you don't have to manipulate the DOM. Create components. Manipulating the DOM this way defeats the purpose for which Blazor was made. You may want to start with some basics at https://learn.microsoft.com/en-us/aspnet/core/blazor/components/?view=aspnetcore-3.1
As #Porkopek mentioned, there's not really a good reason to do this as it more or less defeats the purpose of using Blazor to dynamically render markup.
If you absolutely have to use createElement, you should bind your JS interop code to the window object to invoke:
window.createDivElement = createElement(element, objectReference) {
const newDiv = document.createElement("div");
return element.appendChild(newDiv);
}
Side note, DotNetObjectReference.Create(this) is for calling back into C# component methods via the [JSInvokable] attribute and probably not needed here.

Trying to get vue.js to render something conditionally based on a method in created()

I have a call in my created method which has an await.
I want to know that the results of that call are loaded so that i can conditionally show/hide things in the DOM.
Right now it looks like the DOM is being rendered before that method has completed. But I though that methods in created were called before the DOM rendered?
You're correct in assuming that the created hook runs before the component mounts. However, the lifecycle hooks are not waiting for async calls to complete. If you want to wait for that call to be completed and data to load, you can do so by using a Boolean that you set to true when your data has loaded.
Your template:
<div v-if='dataLoaded'>Now you can see me.</div>
in your vue instace
export default {
data () {
return {
dataLoaded: false
}
},
created () {
loadMyData().then(data => {
// do awesome things with data
this.dataLoaded = true
})
}
}
This way you can keep your content hidden until that call has resolved. Take care with the context when you handle the ajax response. You will want to keep this as a reference to the original vue instance, so that you can set your data correctly. Arrow functions work well for that.

Loading jquery plugin result into Durandal view

I am using the Durandal Starter Template for mvc4. I have set the following simple View:
<section>
<h2 data-bind="html: displayName"></h2>
<h3 data-bind="html: posts"></h3>
<button data-bind="click: getrss">Get Posts</button>
<div id="rsstestid" ></div>
</section>
and ViewModel:
define(function (require) {
var http = require('durandal/http'),
app = require('durandal/app');
return {
displayName: 'This is my RssTest',
posts: ko.observable(),
activate: function () {
return;
},
getrss: function () {
$('#rsstestid').rssfeed('http://feeds.reuters.com/reuters/oddlyEnoughNews');
return;
}
};
});
As you can see, it is simply using the zRssReader plugin to load posts into a div when the 'Get Posts' button is clicked. Everything works fine, the display name is populated and the posts show up as expected.
Where I am having trouble is when I try to eliminate the button and try to load the posts at creation time. If I place the plugin call in the activate function, I get no results. I assume this is because the view is not fully loaded, so the element doesn't exist. I have two questions:
How do I delay the execution of the plugin call until the view is fully composed?
Even better, how do I load the plugin result into an the posts observable rather than using the query selector? I have tried many combinations but no luck
Thanks for your help.
EDIT** the below answer is for durandal 1.2. In durandal 2.0 viewAttached has changed to attached
Copy pasted directly from durandaljs.com
"Whenever Durandal composes, it also checks your model for a function called viewAttached. If it is present, it will call the function and pass the bound view as a parameter. This allows a controller or presenter to have direct access to the dom sub-tree to which it is bound at a point in time after it is injected into its parent.
Note: If you have set cacheViews:true then viewAttached will only be called the first time the view is shown, on the initial bind, since technically the view is only attached once. If you wish to override this behavior, then set alwaysAttachView:true on your composition binding."
--quoted from the site
There are many ways you can do it but here is just 1 quick and dirty way:
<section>
<h2 data-bind="html: displayName"></h2>
<h3 data-bind="html: posts"></h3>
<button data-bind="click: getRss">Get Posts</button>
<div id="rsstestid"></div>
</section>
and the code:
define(function (require) {
var http = require('durandal/http'),
app = require('durandal/app');
var $rsstest;
return {
displayName: 'This is my RssTest',
posts: ko.observable(),
viewAttached: function(view) {
$rssTest = $(view).find('#rsstestid');
},
getRss: function() {
$rssTest.rssfeed('http://feeds.reuters.com/reuters/oddlyEnoughNews');
}
};
});
In general, I think it's wise to refrain from directly touching UI elements from within your view model.
A good approach is to create a custom KO binding that can render the rss feed. That way, you're guaranteed that the view is in place when the binding executes. You probably want to have the feed url exposed as a property on your view model, then the custom binding can read that when it is being updated.
Custom bindings are pretty simple - if I can do it, then it must be :)
Here's a link to the KnockOut custom bindings quickstart: http://knockoutjs.com/documentation/custom-bindings.html
I too am having the same problem, I'm trying to set a css property directly on an element after the durandal view model and view are bound together. I too assume that it's not working because the view is not fully composed at the point I am setting the value.
Best I have come up with is using the viewAttached lifecycle event in durandal, which I think is the last event in the loading cycle of a durandal viewmodel, and then using setTimeout to delay the setting of the property still further.
It's a pretty rubbish workaround but it's working for now.
var viewAttached = function (view) {
var _this = this;
var picker = new jscolor.color($(view).children('.cp')[0], {
onImmediateChange: function() {
_updateCss.call(_this, this.toString());
}
});
picker.fromString(this.color());
setTimeout(function() {
_updateCss.call(_this, _this.color());
}, 1000);
};
var activate = function (data) {
system.log('activated: ' + this.selectors + ' ' + this.color());
};
var deactivate = function (isClose) {
system.log('deactivated, close:' + isClose);
};
return {
viewAttached: viewAttached,
deactivate: deactivate,
activate: activate,
color: this.color
};
I was having a similar issue with timing. On an initial page load, where a partial view was being loaded on the page I could call the viewAttached function and use jQuery to bind some elements within the partial view. The timing worked as expected
However, if I navigated to a new page, and then back to the initial page, the same viewAttached + jQuery method failed to find the elements on the page... they had not yet been attached to the dom.
As best as I have been able to determine (so far) this is related to the transition effects in the entrance.js file. I was using the default transition which causes an object to fade out and a new object to fade in. By eliminating the fadeOutTransition (setting it to zero in entrance.js) I was able to get the viewAttached function to actually be in sync with the partial views attachment.
Best guess is that while the first object is fading out, the incoming object has not yet been attached to the dom but the viewAttached method is triggered anyway.

Sencha touch suitable document.ready type function

In Jquery theres a function
$(document).ready(function (){..}
Is there such a thing in Sencha Touch 2?
I'm aware of
Ext.Setup({ onReady: function () {...} })
However I can only call Ext.Setup once. If I have multiple views how would I take care of this? I would like a function to load when a view is loaded. Do I have to this via a controller? Can I use a snippet of code injected into the index.html (The platform is built on node and requires this)?
Inside of your controller that requires the view just add an init: function() { //do something }, extjs will take care of the rest... usually if your trying to call a function that requires the view to be loaded, then add the 'painted' listener to your view and it will be called when the view is rendered