Registering EVent Listeners inside the dojo .addOnload Method or declaraitevly - dojo

What is the difference between using registering Event Listeners inside the dojo .addOnload Method or declaraitevly registering them ??
For example i have a Button as shown
<button dojoType="dijit.form.Button" id="buttonTwo">
Show Me!
</button>
1st Approach :
dojo.addOnLoad(function() {
var widget = dijit.byId("buttonTwo");
dojo.connect(widget, "onClick", function(){
alert('ddddd');
});
2nd Approach :
<button dojoType="dijit.form.Button" id="buttonTwo" onClick="callMe()">
Show Me!
</button>

There is no practical difference, it is a matter of how you prefer to organize your code.
Having said this, I believe you should avoid mixing declarative and programmatic approaches in Dojo, in order to have a more coherent code base. Which means if you chose the programmatic route, you should do something like this, instead of your 1st approach:
dojo.addOnLoad(function() {
new dijit.form.Button(
{
label: "Show Me!",
onClick: function() {
alert('ddddd');
}
},
'buttonTwo'
);
});
...
<button id="buttonTwo"></button>
This example is a full programmatic example. Depending on your preference you can use it (instead of your 1st approach), or use your second approach. You can read more about the differences in programmatic and declarative Dojo approaches here.

Related

Create a modal for a card

I have a page with a series of cards. Each card has a button to open a modal with some options. Which way would be more efficient at serving the modal?
Store the HTML of the modal on the page once. Emit an event from each card and load the single modal (passing in any relevant data such as the card id that emitted the event).
Have a modal for each card but hide it with v-if so it's not rendered. It's unlikely that the modal will be opened often anyway.
Something else?
Thank you for your thoughts.
In my opinion it's unlikely that there would be significant performance problems with a bunch of cards and dialogs whichever way you go. Both of your proposed solutions would work fine performance wise. This means you could decide based on other very important factors.
I believe the second solution is preferable because it encapsulates the behavior better, and does not push the responsibility of displaying the modal dialog to the parent of all cards. It also scales better, because if you had lets say slightly different types of modal dialogs, you would have an option to simply use different dialog component in different cards easily. You would not have to deal with either giving parent even more responsibility (having to decide which dialog component to display), or deal with having one dialog component which would have to do too much because of the need to display different types of contents.
I would also advise you to take a look at the portal-vue, which would allow you to use your dialogs as part of your cards, and at the same time render them wherever you need in the DOM. For example in the end of the root element of your application (or even in your parent component).
In my opinion, the better way must be something like that:
<template>
<div>
<div v-for="card in cards">
<span>Card: {{ card }} </span>
<button #click="open(card)">Open</button>
</div>
<dialog open v-if="cardSelected">
CardSelected: {{ cardSelected }}
<button #click="close">Close</button>
</dialog>
</div>
</template>
<script>
export default {
name: 'app',
data: () => ({
cards: [1, 2, 3, 4, 5],
cardSelected: null,
}),
methods: {
open(card) {
this.cardSelected = card;
},
close() {
this.cardSelected = null;
},
},
};
</script>
Maybe the dialog must be a diferente component.
I think that way seems to option 1.

Custom element based on bootstrap-toggle not updating attribute binding

I have created a custom element based on bootstrap-toggle that looks as follows:
toggle.ts:
import {bindingMode, bindable, customElement} from "aurelia-framework";
#customElement('toggle')
export class Toggle {
#bindable({ defaultBindingMode: bindingMode.twoWay }) checked;
input;
attached() {
$(this.input).bootstrapToggle();
}
}
toggle.html:
<template>
<require from="bootstrap-toggle/css/bootstrap2-toggle.min.css"></require>
<require from="bootstrap-toggle"></require>
<input ref="input" data-toggle="toggle" type="checkbox" checked.bind="checked">
</template>
The problem ist that the binding for the checked attribute is never updated when the switch is toggled via the UI. I am aware of the common pitfalls when using Aurelia with jQuery based components as described here. However, in my understanding this should not apply to bootstrap-toggle, as this component triggers a change event on the input element on toggle. I have verified that this change event bubbles up to my custom component.
The workaround I currently use is this:
toggle.ts:
import {bindingMode, bindable, customElement} from "aurelia-framework";
#customElement('toggle')
export class Toggle {
#bindable({ defaultBindingMode: bindingMode.twoWay }) checked;
input;
attached() {
$(this.input).bootstrapToggle().on('change', (event) => this.checked = event.target.checked);
}
}
However, I do not understand why this should be necessary.
I have created a test project based on Aurelia's navigation-skeleton that can be downloaded here.
I would appreciate some help in understanding this!
The event listener used by jquery uses the capture phase and presumably does preventDefault or something among those lines that prevents the event from bubbling back up.
The change event dispatched by this line: if (!silent) this.$element.change() does not actually propagate to the bubble phase. Aurelia uses the bubble phase and thus never receives the event.
You can see the difference if you dispatch one manually in your browser console like so:
document.querySelector("[data-toggle]").dispatchEvent(new CustomEvent("change"));
This will result in the appropriate listeners being invoked and updates the bound property.
What this line does: .on('change', (event) => this.checked = event.target.checked); is also add a listener on the capture phase which then of course works. But then you might as well remove the checked.bind='checked' because that effectively does nothing.
There isn't necessarily any straight-forward fix for this, these CSS frameworks tend to just have very intrusive javascript. I would generally recommend against including their scripts and look for (or implement) them natively in Aurelia. It's very easy to do so and just works a lot better.

Best way to load page data into div with VueJS

I have been doing a lot of VueJS tutorials including the router, event bus, and trying to use fetchival and axios to no avail.
The setup, I want there to be two sections. One where I have buttons and the second section would be updated with html data from html files that varies depending on the button pressed.
I have used event bus to be able to just update the second div with basic, static html
(i.e. <p>got it</p>) but I cannot, for the life of me, use any request to get html from another website or file and load it into the div.
I don't necessarily need anyone to build it for me, but even some guidance and direction would be infinitely appreciated.
Based on your comments above, I think you want to change your thinking from "loading html files" to "showing different parts of the Vue component."
Here's a basic example. I'm going to use Vue single-file component syntax, but it's not hard to refactor for class-based components:
<template>
<div>
<button #click="clickedShowFirst">Show First</button>
<button #click="clickedShowSecond">Show Second</button>
<div v-if="showingFirst">
This is the first section!
</div>
<div v-else>
This is the second section!
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
// We default to showing the first block
showingFirst: true
}
}
methods: {
clickedShowFirst: function () {
this.showingFirst = true
},
clickedShowSecond: function () {
this.showingFirst = false
}
}
}
</script>
You could of course make each of the v-if blocks components of their own that you import (which makes sense if they are complex themselves).
Or as suggested by Phillipe, you can use vue-router and make each of those views a different page with a different URL.
One last recommendation to leave you with, I found Jeffrey Way's Laracasts series on Vue.js amazingly helpful when I was learning. His episode titled "Exercise #3: Tabs" is very similar to what you're asking here.
You could use vue-router (https://router.vuejs.org/en/). In first section put the router-link (https://router.vuejs.org/en/api/router-link.html), your buttons, in second section put the router-view (https://router.vuejs.org/en/api/router-view.html).

How do I update semantic ui dropdown list with vue?

I'm trying to update the semantic ui dropdown with new values. Vue is correctly being updated and I'm refreshing the semantic ui dropdown but it still isn't updating. I saw another post which mentioned the use of key, but it still fails.
Template
<div id=root>
<label>Type:</label>
<select id="app_type" class="ui search selection dropdown" v-model="model_type_val">
<option v-for="model_type in model_types" v-bind:value="model_type.value" v-bind:key="model_type.value">{{model_type.text}}</option>
</select>
<p>
selected: {{model_type_val}}
</p>
</div>
Code
var model_types2= [
{value:"",text:"Type"},
{value:"type1",text:"Type1a"},
{value:"type2",text:"Type2a"},
{value:"type3",text:"Type3a"},
{value:"type4",text:"Type4"}
];
var vm2= new Vue({
el:'#root',
data:{
model_type_val:"",
model_types:[
{value:"",text:"Type"},
{value:"type1",text:"Type1"},
{value:"type2",text:"Type2"},
{value:"type3",text:"Type3"}
]
},
mounted: function(){
$('#app_type').dropdown();
setTimeout(function() {
this.model_types=model_types2;
alert(this.model_types[1].text);
$('#app_type').dropdown('refresh');
}, 1000);
}
});
I've tried to reproduce the code in this jsfiddle.
You have a this problem. When you have a callback inside a Vue method or lifecycle hook in which you use this, you need to make sure that this points to the correct object (the Vue). You do that with an arrow function, a closure, or bind.
setTimeout(() => {
this.model_types=model_types2;
$('#app_type').dropdown('refresh');
}, 1000);
Here is your fiddle updated.
Note: In the fiddle, I also converted your selector to use a ref. Typically you want to start weaning yourself off jQuery when working with Vue.
See How to access the correct this inside a callback.

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.