v-on:click in component not working - html

A vue.js component creates a button which should call a function, but the function is never called and the v-on:click is not visible in Chrome's element inspect. My html goes like this:
<bottomcontent></bottomcontent>
And my Vue is like this:
var bottomcontent = {
template: '<div class="bottomcontent"><div class="moreresults" v-on:click="appendcontent">More Results</div></div>'
}
new Vue({
el : 'body',
data : {
homepage:{
numberofdivs: 60
}
},
methods : {
appendcontent: function() {
homepage.numberofdivs += 60
}
},
components: {
'bottomcontent': bottomcontent
}
})

The problem is that methods has to use funcions, not objects.
methods: {
appendcontent: function() {
homepage.numberofdivs += 60
}
}
You also have to correct your markup accordingly.
var bottomcontent = {
template: '<div class="bottomcontent"> <div class="moreresults" v-on:click="appendcontent"> More Results </div></div>'
}

There are some problems lead to the crack.
In the function appendcontent,you should call the data "this.homepage.numberofdivs".
and the correct demo is posted on https://jsfiddle.net/atsknydr/
methods : {
appendcontent: function() {
this.homepage.numberofdivs += 60;
console.log(this.homepage.numberofdivs);
}
}

First, as the warning says:
[Vue warn]: Do not mount Vue to <html> or <body> - mount to normal elements instead.
So, you should create an element like <div id="app"></div> to mount your app instead of <body>.
The problem you are facing is a scope problem. You are trying to call a method from the inside a component scope, that is why it's not finding the method.
Take a look at the docs to understand better.
So, in order to make this work you should change the method from the app scope to the template scope.
Your html:
<body>
<div id="app">
<bottomcontent></bottomcontent>
</div>
</body>
Your js:
<script>
var bottomcontent = {
template: '<div class="bottomcontent"><div class="moreresults" v-on:click="appendcontent">More Results</div></div>',
data: function () {
return {
homepage: {
numberofdivs: 60
}
}
},
methods: {
appendcontent: function () {
console.log('Called method!');
this.homepage.numberofdivs += 60
}
}
}
new Vue({
el: '#app',
components: {
'bottomcontent': bottomcontent
}
})
</script>

Related

Vuejs v-for re-build when update vuex object

I am new to vuejs I want re-build my v-for loop after update vuex object. see following example code.
<div class="row search-result-row" v-for="report in reports" :key="report">
<p>{{ report.description }}</p>
</div>
here is my vuex object called globalReports. when I equal globalReports to reports it doesn't work.
computed: {
updateReports: function() {
return this.reports = this.$store.state.globalReports;
}
},
How can I do this without page reload?
Try with {{updateReports}}. Computed will not be executed util it is monitored or called, just called {{updateReports}}
<div class="row search-result-row" v-for="report in reports" :key="report">
<p>{{ report.description }}</p>
</div>
{{updateReports}}
And don't return anything just update/Assign value of this.reports
computed: {
updateReports: function() {
this.reports = this.$store.state.globalReports;
}
},
by using mapState, you can map the value of globalReports to reports automatically.
Everytime globalReports change, reports gets updated automatically, and the rebuild will happen automatically when it gets updated.
<script>
import { mapState } from "vuex";
export default {
computed: mapState({
reports: "globalReports"
})
};
</script>
Vuex is reactive so when you update the state,this change will affect all components where you use the state properties.To be more specific:
I will show you an example:
//VUEX STORE
state: {
property1
},
getters: {
getProperty1(state) {
return state.property1
}
},
mutations: {
setProperty1(state, payload) {
state.property1 = payload
}
},
actions: {
changeProperty1({commit}, payload) {
commit('setProperty1', payload)
}
}
And below is the component in which you interact with state
<template>
<p>this is from state of store {{ getProperty1 }</p>
<input type="text" v-model="value">
<button #click="changeState">Sumbit</button>
</template>
<script>
export default {
data() {
return {
value: ''
}
},
computed: {
getProperty1() {
return this.$store.getters.getProperty1
}
},
methods: {
changeState() {
this.$store.dispatch('changeProperty1', this.value)
}
}
}
</script>
Getters are to get the state properties
Mutations to change the state properties
Actions to perform async code and then to call mutations to change the state
For more please visit vuex docs

How to access child scope?

In the below code, I'm trying to get a console log in the Directive (child scope),I need to get scope details.I tried adding a scope variable to the function in the directive also, but didn't work.
How can I fix this?
myDirective.html
<html ng-app="MyAppdr">
<head>
<script src="angular.js"></script>
<script src="appdr.js"></script>
</head>
<body ng-controller="dirCtrl">
<h1>hello</h1>
<employee-card></employee-card>
<!--div employee-card></div>
<div class="employee-card"></div--->
</body>
<html>
employee_info.html
<b>{{employee.name}}</b> - {{employee.job}}
<br/><br/>
<div ng-show='!!employee.followers'>
followers
<ul>
<li ng-repeat='name in employee.followers'>{{name}}</li>
</ul>
<button ng-click="follow('Galaa')">follow</button>
</div>
</div>
appdr.js
name="MyAppdr";
requires=[];
appdr=angular.module(name,requires);
appdr.controller("dirCtrl",function($scope){
console.log("This is controller dirCtrl");
$scope.employee={
name:"subo",
job:"cat",
followers:["chin","adyakshaka","aluu"]
}
console.log("parent ",$scope);
/*
$scope.follow=function(name){
$scope.employee.followers.push(name);
}
*/
});
appdr.directive("employeeCard",function(){
//$scope.employee={};
console.log("child ",$scope);
return{
templateUrl:'employee_info.html',
restrict:"AEC",
//replace:true,
controller:function($scope){
$scope.follow=function(name){
$scope.employee.followers.push(name);
}
},
scope:true
}
});
For your particular case, using scope: false seems to be sufficient if you are not showing multiple cards in same page.
appdr.directive("employeeCard",function() {
return {
scope: false,
// other attributes
If you need to show multiple cards in same page, use isolated scope and pass in
appdr.directive("employeeCard",function() {
return {
scope: {
employee: '='
},
// other attributes
<employee-card employee="employee"></employee-card>
Move the console.log() inside the controller of the directive.
appdr.directive("employeeCard", function() {
return {
templateUrl: 'employee_info.html',
restrict: "AEC",
//replace:true,
controller: function($scope) {
console.log("child ", $scope);
$scope.follow = function(name) {
$scope.employee.followers.push(name);
}
},
scope: true
}
});
If you will have only one employee card on the page then keep scope: true else if you need to show multiple cards in the same page, use an isolated scope and pass it in the template.
appdr.directive("employeeCard", function() {
return {
templateUrl: 'employee_info.html',
restrict: "AEC",
//replace:true,
controller: function($scope) {
console.log("child ", $scope);
$scope.follow = function(name) {
$scope.employee.followers.push(name);
}
},
scope: {
employee: "="
}
}
});
And in the html use something like
<employee-card employee="employee"></employee-card>
Refer the documentation of directive here

Render Component in iframe using vuejs without src attribute

<iframe id="frame" width="100%" height="100%">
</ifrme>
I want to render component in this iframe. Is there any option of creating html element or rendering component in iframe?
new Vue({
el:'#frame',
store:store,
router:router,
render: component
})
The easiest way for me is to use srcdoc attribute. It loads raw html overriding src attribute.
<template>
<iframe :srcdoc="html"></iframe>
</template>
Update: More detail example: Consider a textarea for a user html input and want to display in an iframe.
<template>
<div id="app">
<textarea v-model="html"></textarea>
<iframe :srcdoc="html"></iframe>
</div>
</template>
<script>
export default {
name: "App",
data(){
return {
html:"<h1>Hello I am H1 block</h1>"
}
}
};
</script>
You can refer below link That helped me a lot.
Here is the link and the code snippets.
Vue.component('i-frame', {
render(h) {
return h('iframe', {
on: { load: this.renderChildren }
})
},
beforeUpdate() {
//freezing to prevent unnessessary Reactifiation of vNodes
this.iApp.children = Object.freeze(this.$slots.default)
},
methods: {
renderChildren() {
const children = this.$slots.default
const body = this.$el.contentDocument.body
const el = document.createElement('DIV') // we will mount or nested app to this element
body.appendChild(el)
const iApp = new Vue({
name: 'iApp',
//freezing to prevent unnessessary Reactifiation of vNodes
data: { children: Object.freeze(children) },
render(h) {
return h('div', this.children)
},
})
iApp.$mount(el) // mount into iframe
this.iApp = iApp // cache instance for later updates
}
}
})
Vue.component('test-child', {
template: `<div>
<h3>{{ title }}</h3>
<p>
<slot/>
</p>
</div>`,
props: ['title'],
methods: {
log: _.debounce(function() {
console.log('resize!')
}, 200)
},
mounted() {
this.$nextTick(() => {
const doc = this.$el.ownerDocument
const win = doc.defaultView
win.addEventListener('resize', this.log)
})
},
beforeDestroy() {
const doc = this.$el.ownerDocument
const win = doc.defaultView
win.removeEventListener('resize', this.log)
}
})
new Vue({
el: '#app',
data: {
dynamicPart: 'InputContent',
show: false,
}
})
https://jsfiddle.net/Linusborg/ohznser9/
I've tried and haven't found a way to mount vue directly on #iframe.
Yet, you can add div to #iframe and mount to that:
// create iframe element
var iframe = document.createElement('iframe')
iframe.id = 'iframe'
// place iframe inside page html
document.documentElement.insertBefore(iframe, document.querySelector('html').firstChild)
// append div to iframe
var container = document.createElement('div')
container.id = 'container'
iframe.contentWindow.document.body.appendChild(container)
// render vue component inside iframe on #container
new Vue({
el: container,
render: h => h(component)
})
Result:
<html>
<iframe id="iframe">
#document
<html>
<head>
</head>
<body><!-- <-- here was <div id="container"></div> -->
<div class="message" style="color: orange;">Hello from Vue component!</div>
</body>
</html>
</iframe>
<head>
</head>
<body>
</body>
</html>
P.s. I've used this code in chrome extension content scripts (javascript injected into pages). If you're going to use
it elsewhere make sure not to break Same-origin policy.
new Vue({
el:'#frame',
store:store,
router:router,
render: component
})
just try to give a name to your route view.
Hope it works

Dynamic ui-sref in directive template Angular Js

In my angular js Application, I have a directive inside a ng-repeat. Directive has a template in which the HTML part is loaded. Inside that template I am declaring a ui-sref Router dynamically setting states!
This does not Work!
I have tried a Fiddle
Without using a Directive ui-sref works Fine. But I need it in Directive's template.
MY HTML PART
<div ng-repeat="sp in obj.PEs">
<div draw-pe proc="{{sp.peId}}"></div>
</div>
<div style="border:1px;" ui-view="properties"></div>
My Script Part
var myApp = angular.module('myApp', ["ui.router"]);
myApp.controller("testCtrl", function($scope) {
$scope.obj = {
"PEs": {
"1": {
"peId": "1",
"peName": "Exp1",
"peDisplayName": "Exp",
"peType": "Exp",
"peCategory": "PE"
},
"2": {
"peId": "2",
"peName": "RN1",
"peDisplayName": "RNull",
"peType": "RN",
"peCategory": "PE"
}
}
}
})
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('Exp', {
url: '/Exp/:peId',
views: {
"properties": {
template: ".<h3>I am Exp ! </h3>",
controller: function($scope, $stateParams) {
var peId = $stateParams.peId;
alert("Peid-> " + angular.toJson($scope.obj.PEs[peId]));
}
}
}
})
.state('RN', {
url: '/RN/:peId',
views: {
"properties": {
template: "<h3> I am RN ! </h3>",
controller: function($scope, $stateParams) {
var peId = $stateParams.peId;
alert("Peid-> " + angular.toJson($scope.obj.PEs[peId]));
}
}
}
})
});
myApp.directive("drawPe", function() {
return {
restrict: "AE",
template: '<div ui-sref="{{peObj.peType}}( { peId:peObj.peId } )"> <h5>{{peObj.peDisplayName}}</h5></div>',
link: function($scope, element, attrs) {
var procId = $scope.$eval(attrs.proc);
alert(procId);
// alert(angular.toJson(scope.obj.processElements[procId]))
$scope.peObj = $scope.obj.PEs[procId];
}
}
})
See the Browser Console, on clicking the output Part!
ERROR
Error: Invalid state ref '( { peId:peObj.peId } )'
What will be the best Practice to call dynamic state names inside directives Template? I Have read some previous asked question and answer, But I am not clear with the idea as I am new to Angular Js.
Any Idea/help appreciated
Thanks
You can use $compile service to compile your directive's template when your scope changes.
Your directive could look like this:
myApp.directive("drawPe", function($compile) {
return {
restrict: "AE",
tranclude: true,
scope: {
peObj: '='
},
template: ' <h5>{{peObj.peDisplayName}}</h5>',
link: function(scope, element, attrs) {
console.log(scope.peObj);
scope.$watch(
function(scope) {
// watch the 'compile' expression for changes
//return scope.$eval(attrs.compile);
},
function(value) {
$compile(element.contents())(scope);
}
);
}
}
});
And your html:
<div ng-repeat="sp in obj.PEs">
<div draw-pe pe-obj="sp" proc="{{sp.peId}}"></div>
</div>
<div style="border:1px;" ui-view="properties"></div>
Working fiddle is here.

using paper-datatable-card in a custom-tag

//index.html
<html>
<head>
<link rel="import" href="test-table.html">
</head>
<body>
<template is="dom-bind" id="index">
<test-table data="{{data}}" ></test-table>
</template>
</body>
</html>
Polymer({
is: "test-table",
properties : {
data : {type : Array},
}
/*I dont know where should I put this stuff
"queryForIds:"
"getByIds :"
"set:"
"length:0"
*/
});
<dom-module id="test-table">
<template>
<paper-datatable-card id="datatableCard" header="Users" page-size="10" data-source="{{data}}" id-property="_id" selected-ids="{{selectedIds}}">
<paper-datatable id="datatable" data='{{data}}' selectable multi-selection selected-items="{{selectedItems}}">
<paper-datatable-column header="Id" property="_id" sortable>
<template>
<span>{{value}}</span>
</template>
</paper-datatable-column>
</paper-datatable>
</paper-datatable-card>
</template>
</dom-module>
as part of single page application I am using “paper-datatable-card” in my own custom-tag. I able to display the records but I’m not getting where I have to put the code for pagination. And I don’t want to put all records into dataSource at a time.
Any help is appreciated,
Thank you,
Venkat.
From within your Polymer component, you can set data in the ready method:
ready: function() {
this.data = {
queryForIds: function(sort, page, pageSize){
// implement me
},
getByIds: function(ids){
// implement me
},
set: function(item, property, value){
// implement me
},
length:0
};
}
Your comment question:
So I am unable to put the code from lines 117 to 133 in my custom elements as it doesnt support dom-bind
Answer (in Polymer 2.0) you can do it in your component constructor all the methods and all the data variables:
class YourComponent extends Polymer.Element {
contructor() {
super();
//in case if you use paper-datatable-card
this.data = {
get: function (sort, page, pageSize) {
return new Promise((resolve, reject) => {
const exampleData = [
{ 'name': 'someName1' },
{ 'name': 'someName2' }
];
resolve(exampleData);
});
},
set: function(item, property, value){...},
length: 1
};
//in case if you use paper-datatable only then without get or set properties
this.data = [ { name: 'someName' } ];
}
}