Vuejs deferred events on ajax content - events

I have some vuejs events.
<div #mouseover="activate" #mouseout="deactivate" class="item featured">
They work fine but when the content is loaded in via a simple jquery load() it does not trigger. How can I defer these events in vuejs?
edit:
The load is triggered by clicking the nav
<li v-on:click="filterTalents" data-department="hardware">
filterTalents: function(event) {
var dept= $(event.target).closest('li').data('department');
$( ".content" ).load( "includes/"+dept+".html", function()
});
},
activate: function(event) {
$(event.target).closest('.item').addClass('active');
},
deactivate: function(event) {
$(event.target).closest('.item').removeClass('active');
},

Given that you want to add class dynamically to an element, you can use dynamic class binding provided by vue.
A simple example would be to pass an object to v-bind:class to dynamically toggle classes:
<div v-bind:class="{ active: isActive }"></div>
The above syntax means the presence of the active class will be determined by the truthiness of the data property isActive.

Related

Magento2 Knockout.js contentUpdated not binding observables after ajax.

I have an issue with observables being fired after content is updated via ajax and javascript is re-initialized via .trigger('contentUpdated'). This all works when the scripts are rendered initially on page load but when they are added via ajax I cannot get the observables to update. For demo purposes I've simplified by logic but basically I have a block that gets loaded via ajax for a product collection like so:
myblock.phtml
<div class="wrapper-id-1">
<!-- this is what gets appended via ajax
<div id="product-item-<?php echo $productId;?>">
<span data-bind="text: someObservable()"></span>
...
</div>
<script type="text/x-magento-init">
{
"#product-item-<?php echo $productId;?>": {
"path/to/component":{
"some":"vars"
}
}
</script>
<!--and ajax append ends here -->
</div>
In the component that gets bound to the element I have:
component.js
...
this.someObservable: ko.observable('default value'),
initialize: function () {
var self = this;
this.anotherComponentModel().value.subscribe(function(data){
self.someObservable(data['value']);
},this);
},
...
the ajax that calls and loads the collection:
ajaxComponent.js
$.ajax({
url: 'route/to/controller?cat=' + categoryId,
success: function (data) {
$('.wrapper-id-' + categoryId).empty().append('<h2>' + categoryTitle + '</h2>' + data).show().trigger('contentUpdated');
}
})
...
I see that the component(component.js) gets initialized when contentUpdated is triggered and it has all of the correct data that is needed. However the observables to not fire and the data is not updated to the DOM. This an issue with scope? Or to I need to re-initialize the observables? I tried doing this via not binding directly to the component ie:
<script type="text/x-magento-init">
{
// components initialized without binding to an element
"*": {
"<js_component3>": ...
}
}
</script>
but it achieves the same result.
What am I missing here.

CanJS on click outside of component effecting component

I would like to add an event listener in in <some-component> that reacts to the button.
<some-component></some-component>
<button class="click">click here</button>
I am sure this is really simple. I am very new to CanJS and working on it.
<can-component tag="some-component">
<style type="less">
<!-- stuff -->
</style>
<template>
<!-- stuff -->
</template>
<script type="view-model">
import $ from 'jquery';
import Map from 'can/map/';
import 'can/map/define/';
export default Map.extend({
define: {
message: {
value: 'This is the side-panels component'
}
}
});
</script>
</can-component>
I tried adding a $('body').on('click', '.click', function() {}); to the component and it didn't seem to work. Been reading a lot of documentation, but I am still missing some fundamental understanding.
UPDATE
I tried this:
<some-component-main>
<some-component></some-component>
<button class="click">click here</button>
</some-component-main>
with the event listener in some-component-main
events: {
".click click": function(){
console.log("here I am");
}
},
But that also didn't work.
<some-component-main>
<some-component></some-component>
<button class="click">click here</button>
</some-component-main>
with the event listener in some-component-main
events: {
".click click": function(){
console.log("here I am");
}
},
This did work once I realized that components ending with a number causes other issues that was preventing it.
You can make things inside your component available to the parent scope using the {^property-name} or {^#method-name} syntax. Read about it here: https://canjs.com/docs/can.view.bindings.toParent.html
Here's a fiddle: http://jsbin.com/badukipogu/1/edit?html,js,output
In the following example, <my-compontent> implements a doSomething method and we the button to call that method when clicked. We expose the method as "doFooBar".
<my-component {^#do-something}="doFooBar" />
<button ($click)="doFooBar">Button</button>
and the code:
can.Component.extend({
tag: "my-component",
template: can.view('my-component-template'),
viewModel: can.Map.extend({
doSomething: function () {
alert('We did something');
}
})
});
But why does the example use ^#do-something="..." instead of ^#doSomething="..."??
DOM node attributes are case insensitive, so there's no way to tell the difference between doSomething="", DoSomEthiNg="", or DOSOMETHING="" - all three are equivalent. CanJS is following the way browsers work by converting attributes with dashes to camelCase and vice versa.
Consider native data attributes - if you do something like <div data-my-foo="my bar">, then the value is accessible via JavaScript by doing [div].dataset.myFoo (notice the camelCasing). The same applies to css properties where css uses "background-color" but javascript uses backgroundColor. CanJS is following this convention.

Kendo-Grid with Angular

I am somewhat new to Angular and trying to learn how to use Kendo Grid without jQuery using Angular. I get the jQuery code that is used for the widget configuration is written in javascript but i am not getting the HTML directives.
<kendo-grid options="mainGridOptions">
What does "options" attribute mean ? I am assuming its an attribute that the kendo-grid (as defined by the directive) widget has ? But when i go the documentation, I don't see it in the configuration of fields drop-down ?
You should use k-options like this...
<kendo-grid k-options="mainGridOptions"></kendo-grid>
... and then on your controller scope you can expose your options object as so.
...
$scope.mainGridOptions = {
dataSource: {
data: myData
},
height: 550
};
...
This is how you reference the options object.
In jQuery based Kendo UI it is passed into the constructor like this...
$('myGrid').kendoGrid({
dataSource: {
data: myData
},
height: 550
});
As a side note, most if not all configuration options are available directly on the directive with the k- prefix.
For Example...
<kendo-grid
k-data-source="myData"
k-height="550"
></kendo-grid>
.. and then you would just expose your data on the controller...
...
$scope.myData
...
Another note is that if you use the directive as an attribute like this...
<div kendo-grid="myGrid"
k-data-source="myData"
k-height="550"
></div>
... you are assigning it a reference allowing you to access the widget's Kendo object in the controller's scope.
...
$scope.myGrid.resize();
...
The attribute k-options can be used to store the whole widget configuration in the controller. This attribute can also be used in other Kendo components like scheduler, date picker etc.
Here an example for Kendo datepicker implemented with the k-options attribute:
<div ng-app="app" ng-controller="MyCtrl">
<input kendo-date-picker k-options="monthPickerConfig">
</div>
<script>
angular.module("app", ["kendo.directives"]).controller("MyCtrl", function($scope) {
$scope.monthPickerConfig = {
start : "year",
depth : "year",
format : "MMMM yyyy"
};
});
</script>

Add element to this.$el before rendering

I have the following template:
<a data-rel="back" data-role="button" data-icon="delete" data-iconpos="notext" class="ui btn-right" data-theme="e"></a> <p id="msg"></p>
which is loaded from the following view:
define(['backbone', 'marionette', 'jquery', 'jquerymobile', 'hbs!templates/Popup'],
function (Backbone, Marionette, $, jqm, template) {
return Backbone.Marionette.ItemView.extend({
attributes: function() {
return {
// For dialogs to work correctly, url will need to be unique
'id' : 'popupMsg',
'data-role': 'popup',
'class': 'ui-content'
};
},
template: template,
initialize: function() {
_.bindAll(this);
},
onBeforeRender: function(){
this.$el.find("#msg").text("{{$ message}}");
}
});
});
I try to add some text in the #msg element of the template by adding the code above in OnBeforeRender event. The reason is that I want to pass a string to be localized from handlebars before the view is rendered.
Is that possible?
Thanks
Unfortunately, the #msg element won't exist until the view is rendered, so trying to set its text in onBeforeRender won't work.
Why can't you make the handlebars expression just a part of the template?

Ember event in one view update another?

I have a small extract from my Ember app here. My page contains a number of views each containing different data each with their own controllers.
I want a search field (in index view) to go in one view which should "talk" to the stationList controller to update the content of the stationList view. This doesn't work. I get an error: TypeError: this.get(...).search is not a function
The logging outputs the name of the contoller I've asked it to use: App.StationListController
I added a second search form inside on the StationList View. This one works just fine. The logging this time outputs a dump of the StationListController object. So I am guessing that the other search form, despite my code (in SearchFormView): controllerBinding : 'App.StationListController', is not correctly setting the controller.
So I guess my question is why not?
How can I route the change on the form field in the one view to call a funciton on another view's controller?
Here's my code:
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<div id="searchForm">search form view search:
{{#view App.SearchFormView}}
{{view App.StationSearchField}}
{{/view}}
</div>
<div id="stationList">{{render stationList}}</div>
</script>
<script type="text/x-handlebars" data-template-name="stationList">
station list view search: {{view App.StationSearchField}}
<ul>
<li>List</li>
<li>will</li>
<li>go</li>
<li>here</li>
</ul>
{{searchTerm}}
</script>
And
App = Ember.Application.create({})
App.SearchFormView = Ember.View.extend({
init : function()
{
console.log("SearchFormView init", this.get('controller'))
}
})
App.StationSearchField = Ember.TextField.extend({
keyUp: function(event) {
var searchTerm = this.value
console.log("value",searchTerm,this.get('controller'))
this.get('controller').search(searchTerm)
}
})
App.StationListController = Ember.ArrayController.extend({
content : [],
searchTerm : null,
search : function(term)
{
this.set("searchTerm",term)
console.log("searching",term)
}
});
Fiddle: http://jsfiddle.net/ianbale/8QbrK/14/
I think the controllerBinding stuff is from the older version, I don't think that works anymore.
You can use controllerFor on get('controller') in the StationSearchField.
this.get('controller').controllerFor('station_list').search(searchTerm)
But controllerFor is deprecated and may be removed. Depending on your application structure you use needs on the controller.
Another way which I am using, is to send a custom event from the View, which the Route then sends to the corresponding controller.
App.IndexRoute = Ember.Route.extend({
events: {
search: function(term) {
controller = this.controllerFor('station_list')
controller.search(term);
}
}
});
and dispatch a search event from view like so.
this.get('controller').send('search', searchTerm);
The advantage of this method is you dispatch the same event from multiple places and it would get handled in the same way.
Here's the updated jsfiddle.

Resources