How to call function dynamically in JQuery - javascript

I've set of html codes, I want to have a function for each set where I can pull some data or do some activities, so basically I need to be calling function according to the html codes present in DOM, suppose I've header section I want to collect menu items and I've sliders where I want to collect slider information, So I need to call header function to do the activity accordingly and slider function to do the activity, I went across some info about eval() but I guess it has lot of demerits and is being obsolete. Please suggest me how can I achieve it.
HTML Code:
Header
<div class="header" data-nitsid="1">
<div class="branding">
<h1 class="logo">
<img src="images/logo#2x.png" alt="" width="25" height="26">NitsOnline
</h1>
</div>
<nav id="nav">
<ul class="header-top-nav">
<li class="has-children">
Home
</li>
</ul>
</nav>
</div>
Slider
<div id="slideshow" data-nitsid="2">
<div class="revolution-slider">
<ul> <!-- SLIDE -->
<!-- Slide1 -->
<li data-transition="zoomin" data-slotamount="7" data-masterspeed="1500">
<!-- MAIN IMAGE -->
<img src="http://placehold.it/1920x1200" alt="">
</li>
</ul>
</div>
</div>
Now I want to collect data from both elements and pass the data to my views of laravel framework where it will generate a popup for each section for editing purpose.
$('.page-content-wrapper').find('[data-nitsid]').each(function() {
// getting data to call function
var nits = $(this).data("nitsid");
// calling function
design.nits();
}
var design = {};
design.1 = function() {
// do ajax request to views of header
}
design.2 = function() {
// do ajax request to views of slider
}

You canot use literal number as a property name. If you want to call property 1 of object design use design[1] instead. Also, you cannot assing property to non-initialized variable, you must use var design = {}; to make it object. If your property of design object is stored in nits variable, then call it as design[nits]();. Also, next time don't forget to test your code before posting it here. You've forget ) after your first function.
$('.page-content-wrapper').find('[data-nitsid]').each(function() {
// getting data to call function
var nits = $(this).data("nitsid");
// calling function
design[nits]();
});
var design = {};
design[1] = function() {
// do ajax request to views of header
};
design[2] = function() {
// do ajax request to views of slider
};

You want to use design[nits]();.
This will get the property nits of design and execute it with ().
But there is another problem. Your design will be declared after the each loop, so it is not available inside. You have to place it before.
$(function() {
var design = {};
design.funcOne = function() {
alert("funcOne called");
}
design.funcTwo = function() {
alert("funcTwo called");
}
$('div[data-nitsid]').each(function() {
var nits = $(this).data("nitsid");
design[nits]();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-nitsid="funcOne">
I will call 'funcOne'!
</div>
<div data-nitsid="funcTwo">
I will call 'funcTwo'!
</div>

Related

Auto Refresh Div container

I have function like:
document.getElementById("IR_0_ph").innerHTML = sent_dict["IR_0"];
and i get this info like: h2 id="IR_0_ph" class="number">0</h2>
All work fine, but he not auto update info, if i manual reloat page all its good, but i need auto update this info.
mb i can refresh just main Div Container or .... ?
function data_handler(sent_dict) {
socket.emit("control_event", {
data: "Hello!"
}); // tell the RPI that the wifi connection is still working
document.getElementById("IR_0_ph").innerHTML = sent_dict["IR_0"];
document.getElementById("IR_1_ph").innerHTML = sent_dict["IR_1"];
document.getElementById("IR_4_ph").innerHTML = sent_dict["IR_4"];
document.getElementById("IR_Yaw_right_ph").innerHTML = sent_dict["IR_Yaw_right"];
document.getElementById("IR_Yaw_left_ph").innerHTML = sent_dict["IR_Yaw_left"];
document.getElementById("Yaw_ph").innerHTML = sent_dict["Yaw"];
document.getElementById("p_part_ph").innerHTML = sent_dict["p_part"];
document.getElementById("alpha_ph").innerHTML = sent_dict["alpha"];
document.getElementById("Kp_ph").innerHTML = sent_dict["Kp"];
document.getElementById("Kd_ph").innerHTML = sent_dict["Kd"];
document.getElementById("blue_percentage_ph").innerHTML = sent_dict["blue_percentage"];
stored_state = document.getElementById("state_table_1_ph").innerHTML;
new_state = sent_dict["AUTO_STATE"];
if (new_state != stored_state) {
insert_into_state_table_ph(new_state);
}
document.getElementById("manual_state_ph").innerHTML = sent_dict["manual_state"];
document.getElementById("mode_ph").innerHTML = sent_dict["mode"];
}
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-lg-3">
<div class="statistic__item">
<h2 id="IR_0_ph" class="number">unknown</h2>
<span class="desc">FRONT SIDE</span>
<div class="icon">
<i class="zmdi zmdi-account-o"></i>
</div>
</div>
</div>
</div>
</div>
1) How data_handler function being called from what way, is it called from some async flow or its just a one time calling function.
2) Where the sent_dict is coming from ?
Not sure How you are calling, and how sent_dict data passing to dataHandler function. Assuming sent_dict is a server call or device response.
There are two use cases or senarios:
1) calling once.
example:
ajaxCall.then(sent_dict => data_handler(sent_dict));
if yes, perform the ajax call in intervals using setTimeout function of javascript.
setTimeout(ajaxCall, interval_time).
or you can use observable interval operator to mimic the same behavior without doing much. which will automatically update the div on each time response gets from server.
2) if it is calling more than once or interval based calling.
following code in not enough to answer your question.

How to push data into array inside a pop up (pop up opens for particular id) using angularjs

I successfully added data to array using push method normally but failed to do so inside a pop up which opens up for a particular Id .
Here is my code:
<div class="form-group">
<label class="col-sm-3" for="pwd">Speciality:</label>
<div class="col-sm-4">
<input type="text" class="form-control" ng-model="spec" id="usr">
<button type="submit" ng-click="addSpeciality()">Add </button>
</div>
<div class="col-sm-5">
<ul>
<li ng-repeat="spec in speciality">
{{ spec }}
<button ng-click="removeSpeciality($index)">Remove</button>
</li>
</ul>
</div>
</div>
Controller code:
$scope.speciality=[];
$scope.addSpeciality = function(){
$scope.speciality.push($scope.spec);
$scope.spec = '';
};
$scope.removeSpeciality = function(index) {
$scope.speciality.splice(index, 1);
};
This is point when you need a Factory. Forget about storing any data in controllers. Really - FORGET! The only proper way to share data across application is to define Factory you like and inject it separately in every place you gonna work with that data.
You should not store data in $scope. $scope itself is an instance bind to DOM element. So only way you access any data from any level of deepness is using $parent what is a great mistake.
Your controller should $inject that Factory and call related methods when you need to change anything in data. Never pass business logic in controllers. They are like Strategy design pattern - place where you only tell what business logic should take place when you got trigger (click for example):
SpecialityFactory.addSpeciality = function () {
SpecialityFactory.specialities.push({});
}
SpecialityFactory.removeSpeciality = function (idx) {
SpecialityFactory.specialities.splice(idx, 1);
}
So it will be much easier to share business logic across your controllers:
// PageController
PageController.prototype.addSpeciality = function () {
SpecialityFactory.addSpeciality();
};
PageController.$inject = ['SpecialityFactory'];
// ModalController
ModalController.prototype.removeSpeciality = function (idx) {
SpecialityFactory.removeSpeciality(idx);
};
ModalController.$inject = ['SpecialityFactory'];
Well, first of all #Apperion is right, read his answer
but to get your code working try to add the controller to your wrapper HTML element
<div class="form-group" ng-controller="ExampleController">
and
with this array your ng-repeat won't work this way, you need to use this way:
<li ng-repeat="spec in speciality track by $index">

Async loading a template in a Knockout component

I'm pretty experienced with Knockout but this is my first time using components so I'm really hoping I'm missing something obvious! I'll try and simplify my use case a little to explain my issue.
I have a HTML and JS file called Index. Index.html has the data-bind for the component and Index.js has the ko.components.register call.
Index.html
<div data-bind="component: { name: CurrentComponent }"></div>
Index.js
var vm = require("SectionViewModel");
var CurrentComponent = ko.observable("section");
ko.components.register("section", {
viewModel: vm.SectionViewModel,
template: "<h3>Loading...</h3>"
});
ko.applyBindings();
I then have another HTML and JS file - Section.html and SectionViewModel.js. As you can see above, SectionViewModel is what I specify as the view model for the component.
Section.html
<div>
<span data-bind="text: Section().Name"></span>
</div>
SectionViewModel.js
var SectionViewModel = (function() {
function SectionViewModel() {
this.Section = ko.observable();
$.get("http://apiurl").done(function (data) {
this.Section(new SectionModel(data.Model)); // my data used by the view model
ko.components.get("dashboard", function() {
component.template[0] = data.View; // my html from the api
});
});
}
return SectionViewModel;
});
exports.SectionViewModel = SectionViewModel;
As part of the constructor in SectionViewModel, I make a call to my API to get all the data needed to populate my view model. This API call also returns the HTML I need to use in my template (which is basically being read from Section.html).
Obviously this constructor isn't called until I've called applyBindings, so when I get into the success handler for my API call, the template on my component is already set to my default text.
What I need to know is, is it possible for me to update this template? I've tried the following in my success handler as shown above:
ko.components.get("section", function(component) {
component.template[0] = dataFromApi.Html;
});
This does indeed replace my default text with the html returned from my API (as seen in debug tools), but this update isn't reflected in the browser.
So, basically after all that, all I'm really asking is, is there a way to update the content of your components template after binding?
I know an option to solve the above you might think of is to require the template, but I've really simplified the above and in it's full implementation, I'm not able to do this, hence why the HTML is returned by the API.
Any help greatly appreciated! I do have a working solution currently, but I really don't like the way I've had to structure the JS code to get it working so a solution to the above would be the ideal.
Thanks.
You can use a template binding inside your componente.
The normal use of the template bindign is like this:
<div data-bind="template: { name: tmplName, data: tmplData }"></div>
You can make both tmplData and tmplName observables, so you can update the bound data, and change the template. The tmplName is the id of an element whose content will be used as template. If you use this syntax you need an element with the required id, so, in your succes handler you can use something like jQuery to create a new element with the appropriate id, and then update the tmplname, so that the template content gets updated.
*THIS WILL NOT WORK:
Another option is to use the template binding in a different way:
<div data-bind="template: { nodes: tmplNodes, data: tmplData }"></div>
In this case you can supply directly the nodes to the template. I.e. make a tmplNodes observable, which is initialized with your <h3>Loading...</h3> element. And then change it to hold the nodes received from the server.
because nodesdoesn't support observables:
nodes — directly pass an array of DOM nodes to use as a template. This should be a non-observable array and note that the elements will be removed from their current parent if they have one. This option is ignored if you have also passed a nonempty value for name.
So you need to use the first option: create a new element, add it to the document DOM with a known id, and use that id as the template name. DEMO:
// Simulate service that return HTML
var dynTemplNumber = 0;
var getHtml = function() {
var deferred = $.Deferred();
var html =
'<div class="c"> \
<h3>Dynamic template ' + dynTemplNumber++ + '</h3> \
Name: <span data-bind="text: name"/> \
</div>';
setTimeout(deferred.resolve, 2000, html);
return deferred.promise();
};
var Vm = function() {
self = this;
self.tmplIdx = 0;
self.tmplName = ko.observable('tmplA');
self.tmplData = ko.observable({ name: 'Helmut', surname: 'Kaufmann'});
self.tmplNames = ko.observableArray(['tmplA','tmplB']);
self.loading = ko.observable(false);
self.createNewTemplate = function() {
// simulate AJAX call to service
self.loading(true);
getHtml().then(function(html) {
var tmplName = 'tmpl' + tmplIdx++;
var $new = $('<div>');
$new.attr('id',tmplName);
$new.html(html);
$('#tmplContainer').append($new);
self.tmplNames.push(tmplName);
self.loading(false);
self.tmplName(tmplName);
});
};
return self;
};
ko.applyBindings(Vm(), byName);
div.container { border: solid 1px black; margin: 20px 0;}
div {padding: 5px; }
.a { background-color: #FEE;}
.b { background-color: #EFE;}
.c { background-color: #EEF;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="byName" class="container">
Select template by name:
<select data-bind="{options: tmplNames, value: tmplName}"></select>
<input type="button" value="Add template"
data-bind="click: createNewTemplate"/>
<span data-bind="visible: loading">Loading new template...</span>
<div data-bind="template: {name: tmplName, data: tmplData}"></div>
</div>
<div id="tmplContainer" style="display:none">
<div id="tmplA">
<div class="a">
<h3>Template A</h3>
<span data-bind="text: name"></span> <span data-bind="text: surname"></span>
</div>
</div>
<div id="tmplB">
<div class="b">
<h3>Template B</h3>
Name: <span data-bind="text: name"/>
</div>
</div>
</div>
component.template[0] = $(data)[0]
I know this is old, but I found it trying to do the same, and the approcah helped me come up with this in my case, the template seems to be an element, not just raw html

Meteor: Reusing a Template With a Chart-Div

I'm using a single template show which doesn't really have any dynamic elements (yet):
<template name="show">
<div class="row">
<div id="container-pie"></div>
</div>
</template>
I have a sidebar, which pulls from my database and creates <a> tags.
My rendered callback has the code which draws a piegraph:
Template.show.rendered = function() {
var datum = this.data.visitors;
var keys = Object.keys(datum);
newAndReturningPie(keys[0], keys[1], datum.new, datum.returning);
}
(this data is being grabbed from iron:router).
Now here's where I need help (note the sidebar template for reference:)
<template name="sidebar">
<div class="ui left demo vertical inverted labeled sidebar menu">
<a class="item" href="{{pathFor 'root'}}">
<i class="home icon"></i>Home
</a>
{{#if anyProperties}}
{{#each this}}
<a href="{{pathFor 'property.show'}}" class="item">
{{name}}
</a>
{{/each}}
{{else}}
<a class="item">
<i class="settings icon"></i>No properties
</a>
{{/if}}
</div>
</template>
I'm using the same template for every object in the #each block. The problem is that the rendered callback captures the data for the first object, and switching context to another one doesn't actually reload or refresh the page.
If I was using just some HTML with {{objectProperty}}, then I know it would dynamically update. But I'm not using any Spacebars tags, just a single div which contains the graph.
What is a simple, elegant way to have the show template re-render/reload after clicking on an <a> tag in the sidebar?
UPDATE: Thanks to #tarmes
Here's my WORKING code:
Template.show.rendered = function() {
var self = this;
controller = Router.current();
self.autorun(function(){
var params = controller.getParams();
Meteor.call('selectedProperty', params._id, function(err, res){
if (!err) {
var datum = res.visitors;
var keys = Object.keys(datum);
newAndReturningPie(keys[0], keys[1], datum.new, datum.returning);
}
});
});
}
All I did was add a Meteor method to query the DB for the object via ID.
How about something like this:
Template.show.rendered = function() {
self = this;
controller = Router.current();
self.autorun(function() {
var params = controller.getParams(); // Reactive
var datum = self.data.visitors;
var keys = Object.keys(datum);
newAndReturningPie(keys[0], keys[1], datum.new, datum.returning);
});
}
The autorun will rerun everytime the controller's parameters change (which I assume they will do if there's an _id etc. in the route), thus forcing an update.

Vue JS - Putting Json on data

I want to put my JSON data into Vue data, and a display, why can't I get to work?
compiled: function(){
var self = this;
console.log('teste');
$.ajax({
url: 'js/fake-ws.json',
complete: function (data) {
self.$data.musics = data;
console.log(self.$data.musics);
}
})
}
<div id="playlist" class="panel panel-default">
<div class="panel-body">
<ul>
<li v-repeat="musics.item" >
{{nome}}
</li>
<ul>
<div>
</div>
I can't get the code to work.. why?
I think the problem is that musics is not initially part of your Vue data, so when you set its value using self.$data.musics = data, Vue doesn't know it needs to watch it. Instead you need to use the $add method like this:
self.$set("musics", data);
From the VueJs Guide:
In ECMAScript 5 there is no way to detect when a new property is added to an Object, or when a property is deleted from an Object. To deal with that, observed objects will be augmented with two methods: $add(key, value) and $delete(key). These methods can be used to add / delete properties from observed objects while triggering the desired View updates.
this refers to the whole Vue object, so musics object is already accessible via this.musics. More info here in the VueJS API reference and here in the VueJS guide, and more on this here.
With that in mind the code should look something like this:
var playlist = new Vue({
el: '#playlist',
data:{
musics: '',
}
methods: {
compiled: function(){
var self = this;
console.log('test');
$.ajax({
url: 'js/fake-ws.json',
complete: function (data) {
self.musics = data
console.log(self.musics);
}
})
}
}
And the view would be something like this:
<div id="playlist" class="panel panel-default">
<div class="panel-body">
<ul>
<li v-repeat="musics">
{{nome}}
</li>
<ul>
</div>
</div>
Also look at the code of this example.
you can do that with vue-resource. Include vue-resource.js into your app or html file and:
{
// GET /someUrl
this.$http.get('/someUrl').then(response => {
// get body data
this.someData = response.body;
}, response => {
// error callback
});
}

Categories